实现思路:
在执行涉及多数据源业务操作前,依次开启每个数据源事务,如果执行过程中出现异常,依次回滚开启事务,否则全部提交。
使用方式:
通过自定义拦截器MultiTx.class使用,inventory与mes是要用到的两个数据源名称(MultiTx.class根据com.jfinal.plugin.activerecord.tx.Tx.java的基础上进行了调整)

public class MultiTx implements Interceptor{
public static Config[] getConfigWithTxConfig(Invocation inv) {
TxConfig txConfig = inv.getMethod().getAnnotation(TxConfig.class);
if (txConfig == null)
txConfig = inv.getTarget().getClass().getAnnotation(TxConfig.class);
Config[] config = new Config[txConfig.value().split(",").length];
if (txConfig != null) {
int i=0;
for(String v : txConfig.value().split(",")){
config[i] = DbKit.getConfig(v);
if (config[i] == null)
throw new RuntimeException("Config not found with TxConfig: " + config[i]);
i++;
}
}
return config;
}
protected int getTransactionLevel(Config config) {
return config.getTransactionLevel();
}
public void intercept(Invocation inv) {
Config[] configs = getConfigWithTxConfig(inv);
Boolean[] autoCommits = new Boolean[configs.length];
Connection[] conns=new Connection[configs.length];
try {
int i=0;
for(Config config : configs){
Connection conn = config.getThreadLocalConnection();
if (conn != null) { // Nested transaction support
try {
if (conn.getTransactionIsolation() < getTransactionLevel(config))
conn.setTransactionIsolation(getTransactionLevel(config));
inv.invoke();
return ;
} catch (SQLException e) {
throw new ActiveRecordException(e);
}
}
conn = config.getConnection();
autoCommits[i] = conn.getAutoCommit();
config.setThreadLocalConnection(conn);
conn.setTransactionIsolation(getTransactionLevel(config)); // conn.setTransactionIsolation(transactionLevel);
conn.setAutoCommit(false);
conns[i]=conn;
i++;
}
inv.invoke();
for(Connection conn : conns){
conn.commit();
}
} catch (NestedTransactionHelpException e) {
for(Connection conn : conns){
if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
LogKit.logNothing(e);
}
} catch (Throwable t) {
for(Connection conn : conns){
if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
}
throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
}
finally {
int i=0;
for(Connection conn : conns){
try {
if (conn != null) {
if (autoCommits[i] != null)
conn.setAutoCommit(autoCommits[i]);
conn.close();
}
} catch (Throwable t) {
LogKit.error(t.getMessage(), t); // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
}
finally {
configs[i].removeThreadLocalConnection(); // prevent memory leak
}
i++;
}
}
}
}