Spring 事务管理 DataSourceTransactionManager 和 DataSourceTransactionManager
?
如果一个方法中既用了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代码
?
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呢:
?
?
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);
??? }