首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

JDBCTemplate跟HibernateTemplate事物源码解析

2012-12-22 
JDBCTemplate和HibernateTemplate事物源码解析由于项目中对批量的sql进行入库处理。所以打算用jdbcTemplate

JDBCTemplate和HibernateTemplate事物源码解析

由于项目中对批量的sql进行入库处理。所以打算用jdbcTemplate。在其他的增删改查中都是用hibernateTemplate。

在这里考虑到一个问题,就是当jdbcTemplate和hibernateTemplate结合用的时候,事物是怎么样的了?

经过测试:在一个方法中同时使用jdbcTemplate,和hibernateTemplate对数据进行增加操作。然后抛出异常。

发现事物是可以正常回滚的。但为什么可以这样了?看了下源码终于了解了一些。

<beanid="oaTM" style="margin: 0cm 0cm 0pt;">总而言之。不管是使用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("Transactionalresources");

/* */

/* 83 */ private static finalThreadLocal<List<TransactionSynchronization>> synchronizations = new NamedThreadLocal("Transactionsynchronizations");

/* */

/* 86 */ private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal("Currenttransaction name");

/* */

/* 89 */ private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal("Currenttransaction read-only status");

/* */

/* 92 */ private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal("Current transaction isolation level");

/* */

/* 95 */ private static finalThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal("Actual transaction active");

在OpenEntityManagerInViewFilter,OpenSessionInViewInterceptor等需要获取当前线程对象的类中都用到了此类。

在使用hibernateTemplate可以使用hibernateTemplate.sessionFactory.getCurrentSession().connection获取当前的connection对象

在使用jdbcTemplate获取当前的connection对象的方法是:

public abstract class DataSourceUtils {

public static ConnectiondoGetConnection(DataSource dataSource) throws SQLException {

Assert.notNull(dataSource,"No DataSource specified");

//①首先尝试从事务同步管理器中获取数据连接

ConnectionHolderconHolder =

(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

if(conHolder != null && (conHolder.hasConnection() ||

conHolder.isSynchronizedWithTransaction())) {

conHolder.requested();

if(!conHolder.hasConnection()) {

logger.debug("Fetchingresumed JDBC Connection from DataSource");

conHolder.setConnection(dataSource.getConnection());

}

returnconHolder.getConnection();

}

//②如果获取不到连接,则直接从数据源中获取连接

Connectioncon = dataSource.getConnection();

//③如果拥有事务上下文,则将连接绑定到事务上下文中

if(TransactionSynchronizationManager.isSynchronizationActive()) {

ConnectionHolder holderToUse =conHolder;

if(holderToUse == null) {

holderToUse= new ConnectionHolder(con);

}

else{holderToUse.setConnection(con);}

holderToUse.requested();

TransactionSynchronizationManager.registerSynchronization(

newConnectionSynchronization(holderToUse, dataSource));

holderToUse.setSynchronizedWithTransaction(true);

if(holderToUse != conHolder) {

TransactionSynchronizationManager.bindResource(

dataSource, holderToUse);

}

}

returncon;

}

}

当在同在方法中打印出这两个种方法获取的connection对象是同一对象时,基本上证明了在使用jdbcTemplate和hibernateTemplate的时候。

在事物的完整性方面来说是没有问题的。下面我们在看看org.springframework.orm.hibernate3.HibernateTransactionManager。

.HibernateTransactionManager 的父类是PlatformTransactionManager。

.HibernateTransactionManager有很多子类,实现了事物的管理:

CciLocalTransactionManage.

DataSourceTransactionManage.

HibernateTransactionManage.

JdoTransactionManage.

JpaTransactionManage.

public abstract interface PlatformTransactionManager

{

//事物状态

public abstract TransactionStatusgetTransaction(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 */ SessionHoldersessionHolder =

/* 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 */ Sessionsession = 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 newDataAccessResourceFailureException(

/* 453 */ "Could not obtain Hibernate-managed Session forSpring-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. TransactionInfotxInfo = 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. TransactionInfotxInfo = 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 rollbackexception", ex);

/* 415 */ ex2.initApplicationException(ex);

/* 416 */ throw ex2;

/* */ }

/* */ catch (RuntimeException ex2) {

/* 419 */ this.logger.error("Application exception overridden by rollbackexception", ex);

/* 420 */ throw ex2;

/* */ }

/* */ catch (Error err) {

/* 423 */ this.logger.error("Application exception overridden by rollbackerror", ex);

/* 424 */ throw err;

/* */ }

/* */ }

1 楼 shmily2038 2012-11-01   在一个方法中同时使用jdbcTemplate,和hibernateTemplate对数据进行增加操作。然后抛出异常。发现事物是可以正常回滚的。 
总结:使用jdbcTemplate和hibernateTemplate拥有一样的统一的事物一致性,可以放心的结合使用。 2 楼 m635674608 2012-11-02   shmily2038 写道在一个方法中同时使用jdbcTemplate,和hibernateTemplate对数据进行增加操作。然后抛出异常。发现事物是可以正常回滚的。 
总结:使用jdbcTemplate和hibernateTemplate拥有一样的统一的事物一致性,可以放心的结合使用。
放心的结合使用不能这样说啊。。如果不牵扯到hibrnate的缓存的话,可以放心使用。如果同时对缓存对象操作的话,hibernate的缓存不能及时更新,会有问题的。 3 楼 shmily2038 2012-11-02   m635674608 写道shmily2038 写道在一个方法中同时使用jdbcTemplate,和hibernateTemplate对数据进行增加操作。然后抛出异常。发现事物是可以正常回滚的。 
总结:使用jdbcTemplate和hibernateTemplate拥有一样的统一的事物一致性,可以放心的结合使用。
放心的结合使用不能这样说啊。。如果不牵扯到hibrnate的缓存的话,可以放心使用。如果同时对缓存对象操作的话,hibernate的缓存不能及时更新,会有问题的。
呵呵,也是,不过查询的话,倒是可以放心使用就是。

热点排行