HibernateTransactionManager事务管理

来源:互联网 发布:ubuntu winccp 编辑:程序博客网 时间:2024/04/29 19:46

博客分类: 
  • Hibernate
  • HibernateDAOSpringMySQLJDBC 
    如果一个方法中既用了HibernateTemplate,又用了JdbcTemplate,应该怎么配单实例的db事务呢(多例免谈)用 DataSouceTransactionManager是不行的,而用HibernateTransactionManager就可以保证 
    原因的话看下它们源代码,会发现HibernateTransactionManager中的处理可以保证SessionFactoryUtil和datasourceutil都能在一个事务里取到同一个连接 

    原文如下===================================================================== 

    今天这边报出一个问题,他在一个service方法里面,用了jdbcdaosupport的dao又用了hibernateDaoSupport的dao,在spring里面给service方法配上了事务, 

    但是通过mysql的bin log,发现这种不同的dao使用的连接id不是同一个,即jdbctemplate使用了一个链接,而hibernatetemplate使用了另外一个链接,这样虽然两种dao都是针对一个mysql实例,但却没法保证事务。 

    之前xd提过使用hibernateTransaction manager,可以保证混用时候的事务,但是却不知道为啥会这样。我们这边就以为datasourcetransactionmanager也是一样,但发现事实上不一样。确实我们换成hibernateTransaction manager,两种dao使用的connection就归一了,真好,但是为啥呢? 

    翻了半天spring的源代码终于找到了。 

    以下是datasourceTransactionManager的doGetTransaction和doBegin代码 

    Java代码  收藏代码
    1. protected Object doGetTransaction() {  
    2.   
    3. //只是设定一个dataSource为key的存放connection的threadlcal  
    4.    DataSourceTransactionObject txObject = new DataSourceTransactionObject();  
    5.    txObject.setSavepointAllowed(isNestedTransactionAllowed());  
    6.    ConnectionHolder conHolder =  
    7.       (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);  
    8.    txObject.setConnectionHolder(conHolder, false);  
    9.    return txObject;  
    10. }  
    11.   
    12. protected void doBegin(Object transaction, TransactionDefinition definition) {  
    13.      .....  
    14.   
    15.    try {  
    16.     if (txObject.getConnectionHolder() == null ||  
    17.       txObject.getConnectionHolder().isSynchronizedWithTransaction()) {  
    18.      Connection newCon = this.dataSource.getConnection();  
    19.     }  
    20.   
    21. ....  
    22. //从datasource拿一个连接,放入thread生命周期的holder  
    23.   
    24. }  


    这就完了。 

    然后jdbctemplate会通过datasourceutil去拿这个holder里面的connection 

    从而在一个事务里使用这个连接。 

    但是hibernateTransactionManager呢: 

    Java代码  收藏代码
    1. protected Object doGetTransaction() {  
    2.    HibernateTransactionObject txObject = new HibernateTransactionObject();  
    3.    txObject.setSavepointAllowed(isNestedTransactionAllowed());  
    4.   
    5.    SessionHolder sessionHolder =  
    6.      (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());  
    7.    if (sessionHolder != null) {  
    8.     if (logger.isDebugEnabled()) {  
    9.      logger.debug("Found thread-bound Session [" +  
    10.        SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");  
    11.     }  
    12.     txObject.setSessionHolder(sessionHolder, false);  
    13.    }  
    14.   
    15.    if (getDataSource() != null) {  
    16.     ConnectionHolder conHolder = (ConnectionHolder)  
    17.       TransactionSynchronizationManager.getResource(getDataSource());  
    18.     txObject.setConnectionHolder(conHolder);  
    19.    }  
    20.   
    21.    return txObject;  
    22. }  
    23.   
    24. //两个holder都管!  
    25.   
    26. protected void doBegin(Object transaction, TransactionDefinition definition) {  
    27.      .....  
    28.   
    29.    try {  
    30.     if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {  
    31.      Interceptor entityInterceptor = getEntityInterceptor();  
    32.      Session newSession = (entityInterceptor != null ?  
    33.        getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());  
    34.      if (logger.isDebugEnabled()) {  
    35.       logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +  
    36.         "] for Hibernate transaction");  
    37.      }  
    38.      txObject.setSessionHolder(new SessionHolder(newSession), true);  
    39.     }  
    40.   
    41.     .....  
    42.     //从sessionFactory拿个新session,也会产生一个新连接  
    43.   
    44.     session = txObject.getSessionHolder().getSession();  
    45.   
    46.     if (this.prepareConnection && isSameConnectionForEntireSession(session)) {  
    47.      // We're allowed to change the transaction settings of the JDBC Connection.  
    48.      if (logger.isDebugEnabled()) {  
    49.       logger.debug(  
    50.         "Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");  
    51.      }  
    52.   
    53.      //原来直接把session后面的connection也放入holder  
    54.      Connection con = session.connection();  
    55.      Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);  
    56.      txObject.setPreviousIsolationLevel(previousIsolationLevel);  
    57.     }  

    所以如果使用hibernateTransactionManager的话,就完全可以保证SessionFactoryUtil和datasourceutil都能在一个事务里取到同一个连接!所有的疑问烟消云散了, 
    所以大家还是使用hibernateTransactionManager从而随心所欲的使用jdbctemplate和hibernatetemplate吧

    0 0