我想要实现的
目标是拥有一个事务 bean,实例化两次(或多次),并且每次使用不同的 TransactionManager
(即不同的数据库)。
@Transactional
class MyReusableService {
...
}
@Configuration
class MyConfig {
// here I want to use `transactionManagerForDb1`
@Bean
public MyReusableService myReusableServiceForDb1() { ... }
// here I want to use `transactionManagerForDb2`
@Bean
public MyReusableService myReusableServiceForDb2() { ... }
}
我观察到的
TransactionInterceptor 是委托给 TransactionManager
(TM) 的部分。我发现它有两种使用方式:
-
通过 @EnableJpaRepositories(... transactionManagerRef="...")
。这个机制与我想要的有点相关。但它根本不使用@Transactional。它找到所有的存储库。它为每个存储库实例化一个 TransactionInterceptor
。
-
通过@Transactional
。这里有一个 TransactionInterceptor
(TI) 的单个实例。在每次调用时,它都会通过查看注释来决定使用哪个 TM(当然使用缓存)。此 TI 定义为 ProxyTransactionManagementConfiguration。
我所做的
就是定义我自己的 TI:
@Configuration
public class MyConfiguration {
@SuppressWarnings("serial")
public static class MyTransactionInterceptor extends TransactionInterceptor {
...
}
@Bean
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new MyTransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
return interceptor;
}
}
这似乎有效。 Spring定义的TI不再被实例化。我的是。并且它被使用了。
我的问题
- 为什么上述方法有效? Spring 如何知道我想要覆盖它是 TI?我原本期望有 2 个 TI,并努力使用正确的 TI,也许使用
@Primary
。例如这里。
- 有没有更干净的方法来实现我的目标?我不能说我完全满意,因为我发现这个解决方案有点侵入性。
MyReusableService
实际上驻留在一个库中。并且强迫用户覆盖 TI 并不是自包含的。
What I want to achieve
My objective is to have a transactional bean, instantiated twice (or more), and each time w/ a different TransactionManager
(i.e. a different DB).
@Transactional
class MyReusableService {
...
}
@Configuration
class MyConfig {
// here I want to use `transactionManagerForDb1`
@Bean
public MyReusableService myReusableServiceForDb1() { ... }
// here I want to use `transactionManagerForDb2`
@Bean
public MyReusableService myReusableServiceForDb2() { ... }
}
What I observed
TransactionInterceptor is the piece that delegates to a TransactionManager
(TM). I found it used in 2 ways:
-
Via @EnableJpaRepositories(... transactionManagerRef="...")
. This mechanism relates a bit w/ what I want. But it doesn't use @Transactional
at all. It finds all the repos. And it instantiates one TransactionInterceptor
per repo.
-
Via @Transactional
. Here, there is a single instance of TransactionInterceptor
(TI). And at each invocation, it decides which TM to use by looking at the annotations (using caching of course). This TI is defined ProxyTransactionManagementConfiguration.
What I did
I defined my own TI:
@Configuration
public class MyConfiguration {
@SuppressWarnings("serial")
public static class MyTransactionInterceptor extends TransactionInterceptor {
...
}
@Bean
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new MyTransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
return interceptor;
}
}
This seem to work. The TI defined by Spring is no more instantiated. Mine is. And it is used.
My questions
- Why does the above work? How did Spring know that I wanted to override it's TI? I was expecting to have 2 TIs, and fight to use the right one, maybe using
@Primary
. E.g. like here.
- Is there maybe a cleaner way to achieve my objective? I cannot say I'm entirely satisfied, because I find the solution a bit intrusive.
MyReusableService
resides actually in a lib. And forcing the user to override the TI is not self contained.
发布评论