HibernateTransactionManager和DataSourceTransactionManager

    xiaoxiao2021-03-26  37

    spring中常用的事务管理有DataSourceTransactionManager 和HibernateTransactionManager,他们服务的对象不同,下面来简单说明一下:

    1、DataSourceTransactionManager:此事务管理器是针对传统的JDBC进行事务管理,在spring中是对JdbcTemplate进行事务管理

    2、HibernateTransactionManager:是对hibernate进行事务管理,当在spring中使用HibernateTemplate时,要使用此管理器。

    但是当在service的一个方法中同时使用了JdbcTemplate和HibernateTemplate时,就要使用HibernateTransactionManager了,因为当使用DataSourceTransactionManager时,JdbcTemplate和HibernateTemplate获得的connection并不是同一个,也就没办法对service的方法进行事务管理了。

    如果一个方法中既用了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代码   protected Object doGetTransaction() {      //只是设定一个dataSource为key的存放connection的threadlcal      DataSourceTransactionObject txObject = new DataSourceTransactionObject();      txObject.setSavepointAllowed(isNestedTransactionAllowed());      ConnectionHolder conHolder =         (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);      txObject.setConnectionHolder(conHolder, false);      return txObject;   }      protected void doBegin(Object transaction, TransactionDefinition definition) {        .....         try {       if (txObject.getConnectionHolder() == null ||         txObject.getConnectionHolder().isSynchronizedWithTransaction()) {        Connection newCon = this.dataSource.getConnection();       }      ....   //从datasource拿一个连接,放入thread生命周期的holder      }   这就完了。  然后jdbctemplate会通过datasourceutil去拿这个holder里面的connection  从而在一个事务里使用这个连接。  但是hibernateTransactionManager呢:  Java代码   protected Object doGetTransaction() {      HibernateTransactionObject txObject = new HibernateTransactionObject();      txObject.setSavepointAllowed(isNestedTransactionAllowed());         SessionHolder sessionHolder =        (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());      if (sessionHolder != null) {       if (logger.isDebugEnabled()) {        logger.debug("Found thread-bound Session [" +          SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");       }       txObject.setSessionHolder(sessionHolder, false);      }         if (getDataSource() != null) {       ConnectionHolder conHolder = (ConnectionHolder)         TransactionSynchronizationManager.getResource(getDataSource());       txObject.setConnectionHolder(conHolder);      }         return txObject;   }      //两个holder都管!      protected void doBegin(Object transaction, TransactionDefinition definition) {        .....         try {       if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {        Interceptor entityInterceptor = getEntityInterceptor();        Session newSession = (entityInterceptor != null ?          getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());        if (logger.isDebugEnabled()) {         logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +           "] for Hibernate transaction");        }        txObject.setSessionHolder(new SessionHolder(newSession), true);       }          .....       //从sessionFactory拿个新session,也会产生一个新连接          session = txObject.getSessionHolder().getSession();          if (this.prepareConnection && isSameConnectionForEntireSession(session)) {        // We're allowed to change the transaction settings of the JDBC Connection.        if (logger.isDebugEnabled()) {         logger.debug(           "Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");        }           //原来直接把session后面的connection也放入holder        Connection con = session.connection();        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);        txObject.setPreviousIsolationLevel(previousIsolationLevel);       }   所以如果使用hibernateTransactionManager的话,就完全可以保证SessionFactoryUtil和datasourceutil都能在一个事务里取到同一个连接!所有的疑问烟消云散了,  所以大家还是使用hibernateTransactionManager从而随心所欲的使用jdbctemplate和hibernatetemplate吧

    原文来自:http://www.pinhuba.com/spring/101108.htm

    http://bjyzxxds.iteye.com/blog/427309

    转载请注明原文地址: https://ju.6miu.com/read-350309.html

    最新回复(0)