Spring 事务 小结
2017-12-26 20:55
405 查看
Spring事务的PointcutAdvisor: org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
具体的Advice为:org.springframework.transaction.interceptor.TransactionInterceptor
1. TransactionInterceptor的实现
a. PlatformTransactionManager根据配置来获取
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);
2. 如何获取在Thread.currentThread().threadLocals中的connection?
用DataSourceUtils 获取
在当前Thread有事务时:使用DataSourceUtils 获取的是当前Thread中已经创建好的的connection,将会在事务结束时被close(借了TransactionInterceptor的东风)
在当前Thread没有事务时:获取的connection将是新创建的,那就需要手动的把connection给close掉
3. JdbcTemplate如何避免链接泄漏
无论是当前Thread有没有事务都是能保证connection的及时关闭
这里理解错了,DataSourceUtils.releaseConnection(con, getDataSource());会做以下判断:
是否存在Transaction?
存在:标记一下release,最终会在事务结束时执行connection.close()(也就是说如果存在Transaction则只会关闭一次)
不存在:直接执行connection.close()
这里JdbcTemplate类似于SqlSessionTemplate,总的来说,就是如果存在Transaction则把connection的开闭都交给Transaction去做。
具体的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去做。
相关文章推荐
- Spring 编程式事务和申明式事务选择和使用小结
- spring中事务的小结
- Spring--事务小结
- spring中事务的小结
- spring事务和aop问题小结
- 纯JDBC、Hibernate、Spring的AOP声明式事务管理小结
- spring中事务的小结
- 关于spring声明式事务管理异常处理的测试和小结
- 关于spring声明式事务管理异常处理的测试和小结
- Spring 编程式事务和申明式事务选择和使用小结
- Spring事务配置和事务传播类型
- Spring的事务处理之声明式事务处理
- jdk动态代理引起的spring事务不起作用
- spring hibernate 事务
- Spring 事务管理高级应用难点剖析: 第 3 部分
- 【Spring学习31】Spring事务(1):概述
- spring中@Transactional对于事务异常的处理
- spring事务的传播行为与隔离级别
- spring的事务管理配置
- Spring配置多数据源在配置事务后无效完美解决方案