rss· 投稿· 设为首页· 加入收藏· 繁體版
当前位置: 火魔网 » 程序开发 » JavaEE

HibernateTransactionManage事务管理

如果一个方法中既用了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   
  •   
  • }  
  • 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://bjyzxxds.javaeye.com/blog/427309

    顶一下
    (0)
    踩一下
    (0)