您的位置:首页 > 编程语言 > Java开发

Spring 事务 小结

2017-12-26 20:55 405 查看
Spring事务的PointcutAdvisor: org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor

具体的Advice为:org.springframework.transaction.interceptor.TransactionInterceptor

1. TransactionInterceptor的实现

final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}

a. PlatformTransactionManager根据配置来获取

<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>

b. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

1)从配置出来的数据库连接池中获取connection,然后放入Thread.currentThread().threadLocals

2)并且打开autocommit: con.setAutoCommit(false);

c. retVal = invocation.proceedWithInvocation();

调用chain中的下一个

d. commitTransactionAfterReturning(txInfo);

1)con.commit(); 事务提交

2)con.close(); 关闭连接

3)清空Thread.currentThread().threadLocals中的connection

e. completeTransactionAfterThrowing(txInfo, ex);

txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());


2. 如何获取在Thread.currentThread().threadLocals中的connection?

用DataSourceUtils 获取

在当前Thread有事务时:使用DataSourceUtils 获取的是当前Thread中已经创建好的的connection,将会在事务结束时被close(借了TransactionInterceptor的东风)

在当前Thread没有事务时:获取的connection将是新创建的,那就需要手动的把connection给close掉

3. JdbcTemplate如何避免链接泄漏

无论是当前Thread有没有事务都是能保证connection的及时关闭

public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");

Connection con = DataSourceUtils.getConnection(getDataSource());
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null) {
// Extract native JDBC Connection, castable to OracleConnection or the like.
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
else {
// Create close-suppressing Connection proxy, also preparing returned Statements.
conToUse = createConnectionProxy(con);
}
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
}
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
缺点在于每次操作都需要关闭connection,感觉效率不高

这里理解错了,DataSourceUtils.releaseConnection(con, getDataSource());会做以下判断:

是否存在Transaction?

存在:标记一下release,最终会在事务结束时执行connection.close()(也就是说如果存在Transaction则只会关闭一次)

不存在:直接执行connection.close()

这里JdbcTemplate类似于SqlSessionTemplate,总的来说,就是如果存在Transaction则把connection的开闭都交给Transaction去做。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: