您的位置:首页 > 其它

HibernateTransactionManager事务管理

2015-10-16 09:55 357 查看


博客分类:

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代码


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吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: