[英]Overriding transaction propagation levels for methods having Spring's @transactional
I have multiple methods in my codebase annotated with Spring's @transactional
with different propgation levels (lets ignore the idea behind choosing the propagation levels).我的代码库中有多种方法,用Spring 的
@transactional
注释并具有不同的传播级别(让我们忽略选择传播级别背后的想法)。 Example -例子 -
public class X {
@Transactional(Propagation.NOT_SUPPORTED)
public void A() { do_something; }
@Transactional(Propagation.REQUIRED)
public void B() { do_something; }
@Transactional(Propagation.REQUIRES_NEW)
public void C() { do_something; }
}
Now I have a new use case where I want to perform all these operations in a single transaction ( for this specific use case only, without modifying existing behavior ), overriding any annotated propagation levels.现在我有一个新的用例,我想在单个事务中执行所有这些操作(仅针对此特定用例,不修改现有行为),覆盖任何带注释的传播级别。 Example -
例子 -
public class Y {
private X x;
// Stores application's global state
private GlobalState globalState;
@Transactional
public void newOperation() {
// Set current operation as the new operation in the global state,
// in case this info might be required somewhere
globalState.setCurrentOperation("newOperation");
// For this new operation A, B, C should be performed in the current
// transaction regardless of the propagation level defined on them
x.A();
x.B();
x.C();
}
}
Does Spring provide some way to achieve this ? Spring是否提供了一些方法来实现这一点? Is this not possible ?
这不可能吗?
@Transactional(Propagation.NOT_SUPPORTED) public void A() { A_actual(); } // Call A_actual from A and newOperation public void A_actual() { do_something; }
But this might not be as simple to do as this example (there can be a lot of such methods and doing this might not scale).I do believe the only option is to replace TransactionInterceptor
via BeanPostProcessor
, smth.我相信唯一的选择是通过
BeanPostProcessor
替换TransactionInterceptor
,smth。 like:喜欢:
public class TransactionInterceptorExt extends TransactionInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// here some logic determining how to proceed invocation
return super.invoke(invocation);
}
}
public class TransactionInterceptorPostProcessor implements BeanFactoryPostProcessor, BeanPostProcessor, BeanFactoryAware {
@Setter
private BeanFactory beanFactory;
@Override
public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.addBeanPostProcessor(this);
}
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
if (bean instanceof TransactionInterceptor) {
TransactionInterceptor interceptor = (TransactionInterceptor) bean;
TransactionInterceptor result = new TransactionInterceptorExt();
result.setTransactionAttributeSource(interceptor.getTransactionAttributeSource());
result.setTransactionManager(interceptor.getTransactionManager());
result.setBeanFactory(beanFactory);
return result;
}
return bean;
}
}
@Configuration
public class CustomTransactionConfiguration {
@Bean
//@ConditionalOnBean(TransactionInterceptor.class)
public static BeanFactoryPostProcessor transactionInterceptorPostProcessor() {
return new TransactionInterceptorPostProcessor();
}
}
However, I would agree with @jim-garrison suggestion to refactor your spring beans.但是,我同意@jim-garrison 重构你的spring bean 的建议。
UPD. UPD。
But you favour refactoring the beans instead of following this approach.
但是您更喜欢重构 bean 而不是遵循这种方法。 So for the sake of completeness, can you please mention any issues/shortcomings with this
因此,为了完整起见,您能否提及任何问题/缺点
Well, there are a plenty of things/concepts/ideas in spring framework which were implemented without understanding/anticipating consequences (I believe the goal was to make framework attractive to unexperienced developers), and @Transactional
annotation is one of such things.好吧,spring 框架中有很多东西/概念/想法是在没有理解/预期后果的情况下实现的(我相信目标是让框架对没有经验的开发人员有吸引力),
@Transactional
注释就是其中之一。 Let's consider the following code:让我们考虑以下代码:
@Transactional(Propagation.REQUIRED)
public void doSomething() {
do_something;
}
The question is: why do we put @Transactional(Propagation.REQUIRED)
annotation above that method?问题是:为什么我们要在该方法上方放置
@Transactional(Propagation.REQUIRED)
注释? Someone might say smth.有人可能会说smth。 like this:
像这样:
that method modifies multiple rows/tables in DB and we would like to avoid inconsistencies in our DB, moreover
Propagation.REQUIRED
does not hurt anything, because according to the contract it either starts new transaction or joins to the exisiting one.该方法修改了数据库中的多个行/表,我们希望避免数据库中的不一致,而且
Propagation.REQUIRED
不会伤害任何东西,因为根据合同,它要么开始新事务,要么加入现有事务。
and that would be wrong:那将是错误的:
@Transactional
annotation poisons stacktraces with irrelevant information @Transactional
注释用不相关的信息毒化堆栈跟踪In the most cases developers should not use @Transactional(Propagation.REQUIRED)
- technically we just need a simple assertion about transaction status.在大多数情况下,开发人员不应该使用
@Transactional(Propagation.REQUIRED)
- 从技术上讲,我们只需要一个关于事务状态的简单断言。
Using @Transactional(Propagation.REQUIRES_NEW)
is even more harmful:使用
@Transactional(Propagation.REQUIRES_NEW)
更加有害:
@Transactional(Propagation.REQUIRES_NEW)
, cause now you have two incarnations of the same data within the same thread@Transactional(Propagation.REQUIRES_NEW)
的后果,因为现在您在同一个线程中有相同数据的两个化身In the most cases @Transactional(Propagation.REQUIRES_NEW)
is an indicator that you code requires refactoring.在大多数情况下,
@Transactional(Propagation.REQUIRES_NEW)
指示您的代码需要重构。
So, the general idea about @Transactional
annotation is do not use it everywhere just because we can, and your question actually confirms this idea: you have failed to tie up 3 methods together just because developer had some assumptions about how those methods should being executed.所以,关于
@Transactional
注释的一般想法是不要仅仅因为我们可以在任何地方使用它,而你的问题实际上证实了这个想法:你没有将 3 个方法捆绑在一起只是因为开发人员对这些方法应该如何执行有一些假设.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.