描述:
我遇到这个错误的场景是多数据源,读取第一个数据源的配置表信息,再切换到第二个数据源创建表的时候会报错(主数据源创建表不会报错,第二个数据源增删改查正常):XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state。
再交代一下数据源,事务方面的情况:两个数据源,使用hibernate的sessionFactory管理,事务由于项目使用了activity,使用的是JtaTransactionManager,具体的transactionManager为:bitronixTransactionManager。
解决过程:
报错提示很清晰明了global transaction 在active状态,网上查了不少资料,都是大同小异到处转抄的,并没有实际解决问题,无奈自己倒腾。
既然是事务,那就涉及事务传播,在org.springframework.transaction.TransactionDefinition中定义了几种事务传播行为,最开始想到的是自己手动提交事务,于是设置事务传播属性为:PROPAGATION_REQUIRES_NEW,但是问题依然存在,于是想到使用PROPAGATION_NOT_SUPPORTED,但是使用session提交的时候会抛出:找不到当前JTA transaction的异常。那我们最终可以绕过hibernate,使用jdbc来直接提交,问题得到解决。
下面附上关键代码:
JtaTransactionManager tm = BeanFactory.getBean(BeanAttribute.TRANSACTION_MANAGER);
DefaultTransactionDefinition def = BeanFactory.getObject(DefaultTransactionDefinition.class);
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
TransactionStatus status = tm.getTransaction(def);
Connection connection=null;
Statement statement=null;
try {
PoolingDataSource dataSource = BeanFactory.getBean("dataSource.1");
connection = dataSource.getConnection();
statement = connection.createStatement();
statement.execute("CREATE TABLE second_datasource_table (" +
" `UUID` varchar(32) COLLATE utf8_bin NOT NULL," +
" `OPERSTATUS` varchar(1) COLLATE utf8_bin DEFAULT NULL," +
" PRIMARY KEY (`UUID`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=COMPACT;");
tm.commit(status);
} catch (Exception e) {
tracer.error(e);
tm.rollback(status);
} finally {
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
tracer.error(e);
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
tracer.error(e);
}
}
}