hibernate事务和jdbc事务冲突问题

Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.


原帖:http://blog.csdn.net/zhangliao613/article/details/8277343

在项目中同时用到了JDBC和Hibernate,分别配置了各自的事务,同时配置了不同的tx:annotation-driven。

但是在实际使用中,只有配置在前的tx:annotation-driven起了作用,另外一个tx:annotation-driven不起作用。

===============

http://zhangxiaoming.iteye.com/blog/307670

spring 中 Hibernate 事务和JDBC事务嵌套问题
JDBCHibernateSpring配置管理ORM

最近开发中,遇到了这样一个问题。

1.系统中,事务是有spring管理的。

2.系统中,即用到了JDBC,又用到了Hibernate。

3.spring管理了jdbc事务,也管理了Hibernate事务。


如上3点所述,存在这样的情况:

配置了jdbc事务的service,注入了配置了hibernate事务的service。这时,执行的时候,系统就会抛出异常:
org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC connection found - HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.

但是,由配置了hibernate事务的service,注入了配置了jdbc事务的service。就能正常运行。

不知道大家有没有遇到过类似的问题。一起讨论一下。
================

http://www.iteye.com/topic/37707

最近摸索了一下Hibernate与JDBC(iBATIS)事务整合问题,算是有点收获,写出来和大家讨论一下吧。。。

一般大家都会使用Spring声明型事务 transactionAttributes 为 PROPAGATION_REQUIRED

Hibernate 使用 HibernateTransactionManager 、JDBC(iBATIS) 使用 DataSourceTransactionManager

当需要将它们整合到一个事务中的时候

普通的做法是配置统一的DataSource, Hibernate与JDBC(iBATIS) 都使用HibernateTransactionManager

坛子里有篇帖子已经详细论述了这种整合方案 http://www.iteye.com/topic/11063?page=2

------------------------------------------------------

Hibernate与JDBC(iBATIS) 都使用DataSourceTransactionManager又可不可以呢?

普遍的看法是 NO! 认为DataSourceTransactionManager根本就不处理Hibernate的session,事务当然无法实现。。。

但事实是否真的如此呢?

答案同样是 NO! http://forum.springframework.org/archive/index.php/t-9878.html

Juergen Hoeller:
Just if you proxy your JDBC DataSource with a TransactionAwareDataSourceProxy (available since Spring 1.1 RC1) and pass that proxy to your LocalSessionFactoryBean, you could use DataSourceTransactionManager in combination with Hibernate.

也就是说配置 sessionFactory  的 useTransactionAwareDataSource 为 true

Hibernate与JDBC(iBATIS)  都使用 DataSourceTransactionManager 同样可以保证事务

原理就是保证了 connection 的唯一性。

====================http://www.iteye.com/topic/11063?page=2

楼主以及二楼的朋友的论断错误倒也罢了,那种肯定的,结论性总结的态度很容易误导初学者的学习和理解。

提个小小的建议:下结论前要进行充分的考证,我们技术工作者尤其需要严谨的态度。需要用证据来说话。

jdo dao和jdbc dao能否在同一个事务里这我不太清楚。因为我没用过jdo daosupport。
但是jdbc daosupport和hibernate daosupport却能被wrap到同一个事务里。成立需要几点条件:
1、使用同一个datasource
2、事务交由hibernateTransactionManager管理
3、相关dao以及service需要使用runtime exception体系,使用spring提供的exception可以,自己封装设计的runtime exception体系也行。

与此相关的事务代码片断在HibernateTransactionManager类中。最好可以把DatasourceTransactionManager和HibernateTransactionManager对比来看。
在此贴上几个源码片断,多余的我就不解释了。相信大家一看自明。
HibernateTransactionManager#doGetTransaction
Java代码 复制代码 收藏代码
HibernateTransactionObject txObject = new HibernateTransactionObject();; 
txObject.setSavepointAllowed(isNestedTransactionAllowed(););; 

if (TransactionSynchronizationManager.hasResource(getSessionFactory(););); { 
    SessionHolder sessionHolder = 
            (SessionHolder); TransactionSynchronizationManager.getResource(getSessionFactory(););; 
    if (logger.isDebugEnabled();); { 
        logger.debug("Found thread-bound session [" + sessionHolder.getSession(); + 
                "] for Hibernate transaction");; 
    } 
    txObject.setSessionHolder(sessionHolder, false);; 
    if (getDataSource(); != null); { 
        ConnectionHolder conHolder = (ConnectionHolder); 
                TransactionSynchronizationManager.getResource(getDataSource(););; 
        txObject.setConnectionHolder(conHolder);; 
    } 


return txObject;
[java] view plaincopy
HibernateTransactionObject txObject = new HibernateTransactionObject();;
txObject.setSavepointAllowed(isNestedTransactionAllowed(););;

if (TransactionSynchronizationManager.hasResource(getSessionFactory(););); {
    SessionHolder sessionHolder =
            (SessionHolder); TransactionSynchronizationManager.getResource(getSessionFactory(););;
    if (logger.isDebugEnabled();); {
        logger.debug("Found thread-bound session [" + sessionHolder.getSession(); +
                "] for Hibernate transaction");;
    }
    txObject.setSessionHolder(sessionHolder, false);;
    if (getDataSource(); != null); {
        ConnectionHolder conHolder = (ConnectionHolder);
                TransactionSynchronizationManager.getResource(getDataSource(););;
        txObject.setConnectionHolder(conHolder);;
    }
}

return txObject;
[java] view plaincopy
HibernateTransactionObject txObject = new HibernateTransactionObject();; 
txObject.setSavepointAllowed(isNestedTransactionAllowed(););; 
 
if (TransactionSynchronizationManager.hasResource(getSessionFactory(););); { 
    SessionHolder sessionHolder = 
            (SessionHolder); TransactionSynchronizationManager.getResource(getSessionFactory(););; 
    if (logger.isDebugEnabled();); { 
        logger.debug("Found thread-bound session [" + sessionHolder.getSession(); + 
                "] for Hibernate transaction");; 
    } 
    txObject.setSessionHolder(sessionHolder, false);; 
    if (getDataSource(); != null); { 
        ConnectionHolder conHolder = (ConnectionHolder); 
                TransactionSynchronizationManager.getResource(getDataSource(););; 
        txObject.setConnectionHolder(conHolder);; 
    } 

 
return txObject; 

由此可以看出hibernateTransactionManager可以检测到绑定在当前线程上的connection

HibernateTransactionManager#doBegin
Java代码 复制代码 收藏代码
Connection con = session.connection();; 
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);; 
txObject.setPreviousIsolationLevel(previousIsolationLevel);; 

........... 

if (getDataSource(); != null); { 
    ConnectionHolder conHolder = new ConnectionHolder(con);; 
    if (definition.getTimeout(); != TransactionDefinition.TIMEOUT_DEFAULT); { 
        conHolder.setTimeoutInSeconds(definition.getTimeout(););; 
    } 
    if (logger.isDebugEnabled();); { 
        logger.debug("Exposing Hibernate transaction as JDBC transaction [" + 
                conHolder.getConnection(); + "]");; 
    } 
    TransactionSynchronizationManager.bindResource(getDataSource();, conHolder);; 
    txObject.setConnectionHolder(conHolder);; 

// bind the session holder to the thread 
if (txObject.isNewSessionHolder();); { 
    TransactionSynchronizationManager.bindResource(getSessionFactory();, txObject.getSessionHolder(););; 
}
[java] view plaincopy
Connection con = session.connection();;
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);;
txObject.setPreviousIsolationLevel(previousIsolationLevel);;

...........

if (getDataSource(); != null); {
    ConnectionHolder conHolder = new ConnectionHolder(con);;
    if (definition.getTimeout(); != TransactionDefinition.TIMEOUT_DEFAULT); {
        conHolder.setTimeoutInSeconds(definition.getTimeout(););;
    }
    if (logger.isDebugEnabled();); {
        logger.debug("Exposing Hibernate transaction as JDBC transaction [" +
                conHolder.getConnection(); + "]");;
    }
    TransactionSynchronizationManager.bindResource(getDataSource();, conHolder);;
    txObject.setConnectionHolder(conHolder);;
}
// bind the session holder to the thread
if (txObject.isNewSessionHolder();); {
    TransactionSynchronizationManager.bindResource(getSessionFactory();, txObject.getSessionHolder(););;
}
[java] view plaincopy
Connection con = session.connection();; 
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);; 
txObject.setPreviousIsolationLevel(previousIsolationLevel);; 
 
........... 
 
if (getDataSource(); != null); { 
    ConnectionHolder conHolder = new ConnectionHolder(con);; 
    if (definition.getTimeout(); != TransactionDefinition.TIMEOUT_DEFAULT); { 
        conHolder.setTimeoutInSeconds(definition.getTimeout(););; 
    } 
    if (logger.isDebugEnabled();); { 
        logger.debug("Exposing Hibernate transaction as JDBC transaction [" + 
                conHolder.getConnection(); + "]");; 
    } 
    TransactionSynchronizationManager.bindResource(getDataSource();, conHolder);; 
    txObject.setConnectionHolder(conHolder);; 

// bind the session holder to the thread 
if (txObject.isNewSessionHolder();); { 
    TransactionSynchronizationManager.bindResource(getSessionFactory();, txObject.getSessionHolder(););; 


由此可以看出,在真正启动一个事务时,hbTxnManager会先把connection绑定到当前线程,再绑定session到当前线程,由TransactionSynchronizationManager统一管理。并且上面提到的connection是从session中取得的,也就是说,无论是jdbc dao还是hibernate dao本质上使用的是同一个database connection

因此得出结论:HibernateTransactionManager实际上是可以同时管理由JdbcTemplate或JdbcDaoSupport实现的dao以及HibernateTemplate或HibernateDaoSupport实现的事务的。


Rod Johnson的话:
引用
It is possible--and sometimes useful--to have coordinated transactions for both. Your JDBC transactions will be managed by the HibernateTransactionManager if you work with the same JDBC DataSource in the same transaction. That is, create the SessionFactory using Spring's SessionFactoryBean using the same DataSource that your JdbcTemplates use.

The only issue to watch, of course, is that you may be invalidating your Hibernate cache by JDBC changes. Generally I find it best to use JDBC to update only tables that don't have Hibernate mappings.


Juergen Hoeller的话:
引用
As Rod said, simply keep using HibernateTransactionManager, which auto-detects the DataSource used by Hibernate and seamlessly exposes Hibernate transactions as JDBC transactions for that DataSource. JDBC code that accesses the same DataSource via Spring will automatically participate in such transactions.

Note that you must specify the DataSource for Hibernate via LocalSessionFactoryBean's "dataSource" property to allow HibernateTransactionManager to auto-detect it. Alternatively, you can explicitly pass the DataSource to HibernateTransactionManager's "dataSource" property.

猜你喜欢

转载自278653219.iteye.com/blog/2268926
今日推荐