1
abcbuzhiming 2018-12-17 23:51:52 +08:00
多数据源时的事务一致性属于跨库事务,跨库事务非常麻烦而且绝对不是你描述的这种结构能摆平的,一般的注解式事务只能针对单库,所以你用法就是错的,如果你再 service 层用了 @Transactional,那你就要保证这个 service 里调用的 mapper 都是一个库的,否则的话,就不要在 service 上用 @Transactional
|
2
helloZwq 2018-12-18 09:15:56 +08:00
同楼主,用的 AbstractRoutingDataSource,注解+切面 切换数据源
|
3
choice4 OP @abcbuzhiming
/* 如果你再 service 层用了 @Transactional,那你就要保证这个 service 里调用的 mapper 都是一个库的 */ 我是在 service 层用了 @Transactional, 同时我在测试的时候也保证了这个 service 中的 mapper 都是一个库的,并且手动抛出了异常。 但是不行。因为是根据 dao 层方法上的注解去选择数据源。但是事务的开启是在 service 层, 但是开启一个事务又需要有确定的数据源。由于现在数据源还没有确定下来,也就是 AbstractRoutingDataSource 里面那个 determinkey 方法还没有执行,动态数据源还没有确定下来,(即开启事务的 aop 先于动态选择数据源的 aop 执行了)就出现了如下错误: Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 就是这样了。不知道有没有说明白 |
5
abcbuzhiming 2018-12-18 10:47:57 +08:00
@choice4 我明白了,你的事务管理器不止一个,那你必须明确的在 service 层的 @Transactional 里指定特定的事务管理器,否则就出错
|
6
choice4 OP @abcbuzhiming 对 最开始想弄成一个事务管理器。大概如这中 retrun new DataSourceManager(dynamicDataSource)。
然后就会出现我在 #3 出现的那种错误。 后来我干脆就创建两个 DataSourceManager 的 bean。 比如分别指定 beanName 为 A, B。 然后在 service 层比如我用到 ADao 类。 就使用 @Transactional(transactionManager="A", rollbackFor=xxx.class) 并在 service 层抛出相应异常,但是不能回滚。我 debug 跟断点是 TransactionInterceptor.invoke(MethodInvocation) ----> TransactionAspectJSupport.invokeWithinTransaction(Method, Class, final InvocationCallback) ----> TransactionAspectJSupport.completeTransactionAfterThrowing(TransactionInfo, Throwable) 看到了代码执行了 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); 这一行 。并且是正常执行(这行没有出现异常)。但是事务就是没有回滚,想不明白为什么。难道我插入数据时使用的连接,和抛出异常事务回滚时的连接不一样? |
7
choice4 OP 楼上应该是 DataSourceTransactionManager 不是 DataSourceManager。 打错了
|
8
abcbuzhiming 2018-12-18 13:10:58 +08:00
@choice4 不回滚?你确定你的数据库事务设置没问题吗?变成单数据库,单事务管理器,同样的 serviceImpl 代码看是否回滚
|
9
choice4 OP @abcbuzhiming 确定,不过不知道是不是别的哪里写错了 大致代码意思如下吧
@Configuration class Config{ @Bean("a") @PropertiesConfiguration("...") public DataSource a() {return new DataSource;} @Bean("b") @PropertiesConfiguration("...") public DataSource a() {return new DataSource;} @Bean("dynamicDS") public DataSource dataSource() {new DynamicDataSource(); setMap(asMap(a(), b())); return;} @Bean public SqlSessionFactory fac() {return new SqlSessionFactoryBean(dataSource()).getObject();} @Bean("at") public TransactionManager ma() { return new TransactionManager(a()); // return new TransactionManager(dataSource()); //这种就会出现我在 #3 写的那种情况 } } @Service class Service { @Autowired ADao aDao; @Transactional(transaction="at", rollbackFor=RuntimeException.class) public void insert() { aDao.insert(); throw new RuntimeException(); } } @Mapper interface aDao{ @DataSource("a") //自定义注解,aop 会动态选择 a 数据源 @Insert("......") int insert(); } @SpringbootTest class Test() { @Autowired Service aService; @Junit.Test void test() { aService.insert(); } } 大概就是这个意思的代码吧。 |
10
choice4 OP 空格被吃了
|
11
abcbuzhiming 2018-12-18 16:52:16 +08:00
@choice4 感觉没写错,你单数据库,单事务管理器,确认一下是否能回滚
|
12
choice4 OP @abcbuzhiming 单数据源可以回滚, (我是直接是在创建 SqlSessionFactory bean 的时候 bean.setDataSource(a()))
这种方式设置的 (成功回滚)。 原来动态多数据源的时候相当于是 bean.setDataSource(dynamicDataSource()) (无法回滚) |