基于spring的aop实现读写分离与事务配置
2016-11-11 19:23 hduhans 阅读(1809) 评论(0) 收藏 举报项目开发中经常会遇到读写分离等多数据源配置的需求,在Java项目中可以通过Spring AOP来实现多数据源的切换。
一、Spring事务开启流程
Spring中通常通过@Transactional来声明使用事务,我们先来研究一下Spring是如何开启事务的。调试代码,可以发现进入事务方法体内前,会进入如下代码:
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { ... //开启事务 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); ... //代理拦截,执行实际方法体 retVal = invocation.proceedWithInvocation(); ... //无异常,则执行事务提交 commitTransactionAfterReturning(txInfo); ... } }
可以看出方法createTransactionIfNecessary内创建了事务,断点继续追踪进入createTransactionIfNecessary方法体的tm.getTransaction(txAttr),执行代码如下:
@SuppressWarnings("serial")
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//获取当前上下文的事务
Object transaction = doGetTransaction();
...
//如果当前事务已存在,则根据事务传播行为来处理子事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
...
//这里开启事务
doBegin(transaction, definition);
...
}
}
如果当前事务未开启,则通过方法doBegin进行开启,方法体:
@SuppressWarnings("serial")
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
//如果当前db连接为空,则获取并设置连接
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
if (con.getAutoCommit()) {
...
//关闭sql自动提交
con.setAutoCommit(false);
}
...
//设置当前事务状态已开启
txObject.getConnectionHolder().setTransactionActive(true);
...
//绑定当前db连接到ThreadLocal中,key为dataSource,为后续事务体内获取连接提供支持
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
...
}
}
}
执行到这里事务已经开启,继续事务体内执行其他db操作,进入工具类org.springframework.jdbc.datasource.DataSourceUtils的方法doGetConnection,方法体如下:
public abstract class DataSourceUtils { public static Connection doGetConnection(DataSource dataSource) throws SQLException { ... //如果当前TransactionSynchronizationManager上下文已经存在事务连接资源,则直接使用此连接,否则往下获取连接 ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) { conHolder.requested(); if (!conHolder.hasConnection()) { logger.debug("Fetching resumed JDBC Connection from DataSource"); conHolder.setConnection(dataSource.getConnection()); } return conHolder.getConnection(); } ... //如果当前事务上下文不存在连接,则新获取 Connection con = dataSource.getConnection(); if (TransactionSynchronizationManager.isSynchronizationActive()) { //如果当前事务已开启,则将获取到的连接资源绑定到当前TransactionSynchronizationManager上下文中,供事务体内其他db操作使用 ... if (holderToUse != conHolder) { TransactionSynchronizationManager.bindResource(dataSource, holderToUse); } } } }
所以,使用Spring开启事务,都会在方法体前创建连接并开启事务,事务体内的其他方法均沿用当前上下文的连接,并不会新获取连接,直到事务体运行结束,归还连接。
浙公网安备 33010602011771号