由于项目中对批量的sql进行入库处理。所以打算用jdbcTemplate。在其他的增删改查中都是用hibernateTemplate。
在这里考虑到一个问题,就是当jdbcTemplate和hibernateTemplate结合用的时候,事物是怎么样的了?
经过测试:在一个方法中同时使用jdbcTemplate,和hibernateTemplate对数据进行增加操作。然后抛出异常。
发现事物是可以正常回滚的。但为什么可以这样了?看了下源码终于了解了一些。
<bean id="oaTM" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref bean="oaSessionFactory"/></property>
</bean>
总而言之。不管是使用jdbcTemplate或者是hibernateTemplate都是对jdbc的封装,说白了,对数据库的操作还是
使用connection,在回滚事物的时候还是调用了connection. Rollback方法来进行回滚的。
这一回想,在hibernate中有个sessionFactory. getCurrentSession()方法。调用的当前的线程session。
意思就是用当前的connection来操作数据。
在spring管理中有这么一个类来进行当前线程的数据绑定:TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager
/* */ {
/* 77 */ private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
/* */
/* 80 */ private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");
/* */
/* 83 */ private static final ThreadLocal<List<TransactionSynchronization>> synchronizations = new NamedThreadLocal("Transaction synchronizations");
/* */
/* 86 */ private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal("Current transaction name");
/* */
/* 89 */ private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal("Current transaction read-only status");
/* */
/* 92 */ private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal("Current transaction isolation level");
/* */
/* 95 */ private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal("Actual transaction active");
在OpenEntityManagerInViewFilter,OpenSessionInViewInterceptor等需要获取当前线程对象的类中都用到了此类。
在使用hibernateTemplate可以使用hibernateTemplate.sessionFactory.getCurrentSession().connection获取当前的connection对象
在使用jdbcTemplate获取当前的connection对象的方法是:
public abstract class DataSourceUtils {
…
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//①首先尝试从事务同步管理器中获取数据连接
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()) {
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {holderToUse.setConnection(con);}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(
dataSource, holderToUse);
}
}
return con;
}
…
}
当在同在方法中打印出这两个种方法获取的connection对象是同一对象时,基本上证明了在使用jdbcTemplate和hibernateTemplate的时候。
在事物的完整性方面来说是没有问题的。下面我们在看看org.springframework.orm.hibernate3.HibernateTransactionManager。
.HibernateTransactionManager 的父类是PlatformTransactionManager。
.HibernateTransactionManager有很多子类,实现了事物的管理:
CciLocalTransactionManage.
DataSourceTransactionManage.
HibernateTransactionManage.
JdoTransactionManage.
JpaTransactionManage.
public abstract interface PlatformTransactionManager
{
//事物状态
public abstract TransactionStatus getTransaction(TransactionDefinition paramTransactionDefinition)
throws TransactionException;
//提交
public abstract void commit(TransactionStatus paramTransactionStatus)
throws TransactionException;
//回滚
public abstract void rollback(TransactionStatus paramTransactionStatus)
throws TransactionException;
}
/* */ public class HibernateTransactionManager extends AbstractPlatformTransactionManager
/* */ implements ResourceTransactionManager, BeanFactoryAware, InitializingBean
/* */ {
在这些事物管理实现类中都使用了 TransactionSynchronizationManager.bindResource(key);来获取当前绑定的对象;如SessionHolder
/* */ protected Object doGetTransaction()
/* */ {
/* 430 */ HibernateTransactionObject txObject = new HibernateTransactionObject(null);
/* 431 */ txObject.setSavepointAllowed(isNestedTransactionAllowed());
/* */
/* 433 */ SessionHolder sessionHolder =
/* 434 */ (SessionHolder)TransactionSynchronizationManager.getResource(getSessionFactory());
/* 435 */ if (sessionHolder != null) {
/* 436 */ if (this.logger.isDebugEnabled()) {
/* 437 */ this.logger.debug("Found thread-bound Session [" +
/* 438 */ SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
/* */ }
/* 440 */ txObject.setSessionHolder(sessionHolder);
/* */ }
/* 442 */ else if (this.hibernateManagedSession) {
/* */ try {
/* 444 */ Session session = getSessionFactory().getCurrentSession();
/* 445 */ if (this.logger.isDebugEnabled()) {
/* 446 */ this.logger.debug("Found Hibernate-managed Session [" +
/* 447 */ SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
/* */ }
/* 449 */ txObject.setExistingSession(session);
/* */ }
/* */ catch (HibernateException ex) {
/* 452 */ throw new DataAccessResourceFailureException(
/* 453 */ "Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
/* */ }
/* */ }
/* */
/* 457 */ if (getDataSource() != null) {
/* 458 */ ConnectionHolder conHolder = (ConnectionHolder)
/* 459 */ TransactionSynchronizationManager.getResource(getDataSource());
/* 460 */ txObject.setConnectionHolder(conHolder);
/* */ }
/* */
/* 463 */ return txObject;
/* */ }
在Aop的事物管理中:通过拦截器来对相应的事物进行处理。
在对Spring AOP源码分析中关于AOP代理如何起作用时,我们知道Spring的AOP代理通过invoke回调方法对切入点方法进行拦截处理,这个invoke方法是AOP联盟的方法拦截器MethodInterceptor接口中定义的方法,用于对AOP代理对象的方法进行包装处理。事务拦截器TransactionInterceptor正是通过这个invoke拦截方法实现事务的拦截处理,源码如下:
/* */ public class TransactionInterceptor extends TransactionAspectSupport
/* */ implements MethodInterceptor, Serializable{
1. //事务拦截器的拦截方法
2. public Object invoke(final MethodInvocation invocation) throws Throwable {
3. //通过AOP获取事务的目标类
4. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
5. //通过事务属性源TransactionAttributeSource读取事务的属性配置,即调用上面名称匹配
6. //事务属性源NameMatchTransactionAttributeSource的方法
7. final TransactionAttribute txAttr =
8. getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
9. //获取Spring事务管理IoC容器配置的事务处理器
10. final PlatformTransactionManager tm = determineTransactionManager(txAttr);
11. //获取目标类指定方法的事务连接点
12. final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass);
13. //区分不同类型的PlatformTransactionManager事务处理器,不同类型的事务处理器调用//方式不同。对CallbackPreferringPlatformTransactionManager,需要回调函数来//实现事务的创建和提交,对非CallbackPreferringPlatformTransactionManager来//说,则不需要使用回调函数来实现事务处理。
14. //非CallbackPreferringPlatformTransactionManager类型的事务处理器
15. if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
16. //创建事务,将当前事务状态和信息保存到TransactionInfo对象中
17. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
18. Object retVal = null;
19. try {
20. //沿着拦截器链调用处理,使得最后目标对象的方法得到调用
21. retVal = invocation.proceed();
22. }
23. catch (Throwable ex) {
24. //在调用拦截器拦过程中出现异常,则根据事务配置进行提交或回滚处理
25. completeTransactionAfterThrowing(txInfo, ex);
26. throw ex;
27. }
28. //清除与当前线程绑定的事务信息
29. finally {
30. cleanupTransactionInfo(txInfo);
31. }
32. //通过事务处理器来对事务进行提交
33. commitTransactionAfterReturning(txInfo);
34. return retVal;
35. }
36. //CallbackPreferringPlatformTransactionManager类型的事务处理器
37. else {
38. //通过回调函数对事务进行处理
39. try {
40. //执行实现TransactionCallback接口的doInTransaction回调方法
41. Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
42. new TransactionCallback<Object>() {
43. //实现TransactionCallback接口匿名内部类的回调方法
44. public Object doInTransaction(TransactionStatus status) {
45. //创建和准备事务
46. TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
47. try {
48. //沿着拦截器拦调用
49. return invocation.proceed();
50. }
51. //拦截器链处理过程中产生异常
52. catch (Throwable ex) {
53. //如果事务对异常进行回滚处理
54. if (txAttr.rollbackOn(ex)) {
55. //如果异常时运行时异常,则事务回滚处理
56. if (ex instanceof RuntimeException) {
57. throw (RuntimeException) ex;
58. }
59. //如果不是运行时异常,则提交处理
60. else {
61. throw new ThrowableHolderException(ex);
62. }
63. }
64. //如果事务对异常不进行回滚处理
65. else {
66. //提交处理
67. return new ThrowableHolder(ex);
68. }
69. }
70. //清除当前线程绑定的事务信息
71. finally {
72. cleanupTransactionInfo(txInfo);
73. }
74. }
75. });
76. //对调用结果异常进行处理。
77. //如果是ThrowableHolder类型的异常,则转换为Throwable抛出
78. if (result instanceof ThrowableHolder) {
79. throw ((ThrowableHolder) result).getThrowable();
80. }
81. //如果不是ThrowableHolder类型的异常,则异常不做处理直接抛出
82. else {
83. return result;
84. }
85. }
86. catch (ThrowableHolderException ex) {
87. throw ex.getCause();
88. }
89. }
90. }
completeTransactionAfterThrowing()是事物回滚方法。调用的是父类的方法。
/* */ public abstract class TransactionAspectSupport
/* */ implements BeanFactoryAware, InitializingBean
/* */ {
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex)
/* */ {
/* 404 */ if ((txInfo != null) && (txInfo.hasTransaction())) {
/* 405 */ if (this.logger.isTraceEnabled()) {
/* 406 */ this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
/* 407 */ "] after exception: " + ex);
/* */ }
/* 409 */ if (txInfo.transactionAttribute.rollbackOn(ex)) {
/* */ try {
//这里调用的是: AbstractPlatformTransactionManager的rollback方法。最终调用的相应的子类的doRollback方法。
// 比如用的是hibernateTranactionManager就是调用其中的doRollback方法。
// txObject.getSessionHolder().getTransaction().rollback();这里最终调用的还是Hibernate中Transaction的Rollback方法
//归根揭底,都是调用了connection.rollback().DataSoucreTransactionManager也类似。
/* 411 */ txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
/* */ }
/* */ catch (TransactionSystemException ex2) {
/* 414 */ this.logger.error("Application exception overridden by rollback exception", ex);
/* 415 */ ex2.initApplicationException(ex);
/* 416 */ throw ex2;
/* */ }
/* */ catch (RuntimeException ex2) {
/* 419 */ this.logger.error("Application exception overridden by rollback exception", ex);
/* 420 */ throw ex2;
/* */ }
/* */ catch (Error err) {
/* 423 */ this.logger.error("Application exception overridden by rollback error", ex);
/* 424 */ throw err;
/* */ }
/* */ }