项目里有这么一个需求场景
我们有多个系统,同时要共享一个积分数据,数据库的设计可能是这样的
业务系统数据库A
业务系统数据库B
积分资产数据库:同时存放这A系统和B系统的积分以及用户数据
这时候如果A系统做完一个业务处理后同时要对积分做增加或者减少也就是说在一个sevice中会调用2个数据库操作
serviceHandler {
// 操作数据库A
// 操作积分数据库
}
在这样的情况下如果操作数据库A成功了,但是操作数据库B失败了,如何回滚,我现在的回滚是这么去做的
@Aspect
@Component
public class JFinalTxAop {
@Pointcut(value = "@annotation(com.mr.common.annotation.JFinalTx)")
private void jFinalTx() {}
@Around(value = "jFinalTx()", argNames = "pjp")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Object retVal = null;
Config config = getConfigWithTxConfig(pjp);
if (config == null)
config = DbKit.getConfig();
Connection conn = config.getThreadLocalConnection();
// Nested transaction support
if (conn != null) {
try {
if (conn.getTransactionIsolation() < getTransactionLevel(config))
conn.setTransactionIsolation(getTransactionLevel(config));
retVal = pjp.proceed();
return retVal;
} catch (SQLException e) {
throw new ActiveRecordException(e);
}
}
Boolean autoCommit = null;
try {
conn = config.getConnection();
autoCommit = conn.getAutoCommit();
config.setThreadLocalConnection(conn);
// conn.setTransactionIsolation(transactionLevel);
conn.setTransactionIsolation(getTransactionLevel(config));
conn.setAutoCommit(false);
retVal = pjp.proceed();
conn.commit();
} catch (NestedTransactionHelpException e) {
if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
LogKit.logNothing(e);
} catch (Throwable t) {
if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
}
finally {
try {
if (conn != null) {
if (autoCommit != null)
conn.setAutoCommit(autoCommit);
conn.close();
}
} catch (Throwable t) {
// can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
LogKit.error(t.getMessage(), t);
}
finally {
// prevent memory leak
config.removeThreadLocalConnection();
}
}
return retVal;
}
/**
* 获取配置的事务级别
* @param config
* @return
*/
protected int getTransactionLevel(Config config) {
return config.getTransactionLevel();
}
/**
* 获取配置的TxConfig,可注解到class或者方法上
* @param pjp
* @return Config
*/
public static Config getConfigWithTxConfig(ProceedingJoinPoint pjp) {
MethodSignature ms = (MethodSignature) pjp.getSignature();
Method method = ms.getMethod();
TxConfig txConfig = method.getAnnotation(TxConfig.class);
if (txConfig == null)
txConfig = pjp.getTarget().getClass().getAnnotation(TxConfig.class);
if (txConfig != null) {
Config config = DbKit.getConfig(txConfig.value());
if (config == null)
throw new RuntimeException("Config not found with TxConfig: " + txConfig.value());
return config;
}
return null;
}
}这段代码是我在jfianl论坛里找到的,但数据源的时候是有效的,原理很简单就是在处理一段业务的时候把事务打开,如果失败就回滚,成功就提交,但是我不确定这块在多数据源下是否有效,如果无效那么怎么去修改支持多数据源
还有个问题是,我如果不用多数据源的方式,我调用积分系统扣除或者增加系统用RPC或者HTTP去调用,那么如何保证我两个系统数据的一致性?
项目:JFinal
Db.use("A").tx(() -> Db.use("B").tx(() -> {
// 操作数据库A
// 操作数据库B(积分数据库)
return true;
}));