事务传播特性摘记

在配置Hibernat的事务传播特性比较常用就是REQUIRED,read-only,REQUIRES_NEW,示例代码如下:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="get*" read-only="true" />
		<tx:method name="query*" read-only="true" />
		<tx:method name="find*" read-only="true" />
		<tx:method name="load*" read-only="true" />
		<tx:method name="*REQUIRES_NEW" propagation="REQUIRES_NEW"/>
		<tx:method name="*" propagation="REQUIRED" />
	</tx:attributes>
</tx:advice>

 1、假设有UserService中有代码如下:

public void save(User user){
		
		String code =null;
		try {
			code=codeGenerateService.generateUserCode_REQUIRES_NEW();
		} catch (Exception e) {
			LOG.error(e.getMessage(),e);
		}
	
		user.setUserCode(code);
		baseDao.save(user);
		
	}

    

     在执行过程中后台打印的日志如下:

写道
org.springframework.orm.hibernate3.HibernateTransactionManager - Creating new transaction with name [com.lyl.system.service.UserService.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2015-11-11 10:17:03:DEBUG main org.hibernate.impl.SessionImpl - opened session at timestamp: 5927941831421952
org.springframework.orm.hibernate3.HibernateTransactionManager - Opened new Session [org.hibernate.impl.SessionImpl@86d1da] for Hibernate transaction
org.springframework.orm.hibernate3.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@86d1da]
org.springframework.orm.hibernate3.HibernateTransactionManager - Found thread-bound Session [org.hibernate.impl.SessionImpl@86d1da] for Hibernate transaction
org.springframework.orm.hibernate3.HibernateTransactionManager - Suspending current transaction, creating new transaction with name [com.lyl.system.service.CodeGenerateService.generateUserCode_REQUIRES_NEW]
org.hibernate.impl.SessionImpl - opened session at timestamp: 5927941831806976
org.springframework.orm.hibernate3.HibernateTransactionManager - Opened new Session [org.hibernate.impl.SessionImpl@19977bd] for Hibernate transaction
org.springframework.orm.hibernate3.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@19977bd]
org.hibernate.transaction.JDBCTransaction - begin
org.hibernate.jdbc.ConnectionManager - opening JDBC connection
net.sf.ehcache.CacheManager@6691da net.sf.ehcache.util.UpdateChecker - Checking for update...
org.hibernate.transaction.JDBCTransaction - current autocommit status: true
org.hibernate.transaction.JDBCTransaction - disabling autocommit
Hibernate:
select
codegenera0_.codeType as codeType0_,
codegenera0_.value as value0_
from
demo1_code_generate codegenera0_
where
codegenera0_.codeType=?
org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
org.hibernate.loader.Loader - result row: EntityKey[com.lyl.system.entity.CodeGenerate#USER_CODE]
org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
org.hibernate.engine.TwoPhaseLoad - resolving associations for [com.lyl.system.entity.CodeGenerate#USER_CODE]
org.hibernate.engine.TwoPhaseLoad - done materializing entity [com.lyl.system.entity.CodeGenerate#USER_CODE]
org.hibernate.engine.StatefulPersistenceContext - initializing non-lazy collections
org.springframework.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
org.springframework.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
org.springframework.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
org.springframework.orm.hibernate3.HibernateTransactionManager - Initiating transaction commit
org.springframework.orm.hibernate3.HibernateTransactionManager - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@19977bd]
org.hibernate.transaction.JDBCTransaction - commit
org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections
org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects
org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
org.hibernate.pretty.Printer - listing entities:
org.hibernate.pretty.Printer - com.lyl.system.entity.CodeGenerate{value=8, codeType=USER_CODE}
org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
org.hibernate.SQL -
update
demo1_code_generate
set
value=?
where
codeType=?
Hibernate:
update
demo1_code_generate
set
value=?
where
codeType=?
org.hibernate.cache.UpdateTimestampsCache - Pre-invalidating space [demo1_code_generate]
org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
org.hibernate.cache.UpdateTimestampsCache - Invalidating space [demo1_code_generate], timestamp: 5927941833535488
org.springframework.orm.hibernate3.HibernateTransactionManager - Closing Hibernate Session [org.hibernate.impl.SessionImpl@19977bd] after transaction
org.springframework.orm.hibernate3.SessionFactoryUtils - Closing Hibernate Session
org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
org.springframework.orm.hibernate3.HibernateTransactionManager - Resuming suspended transaction after completion of inner transaction
org.springframework.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
org.hibernate.event.def.AbstractSaveEventListener - generated identifier: 402883e750f6e82e0150f6e833cb0000, using strategy: org.hibernate.id.UUIDHexGenerator
org.springframework.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
org.springframework.orm.hibernate3.HibernateTransactionManager - Initiating transaction commit
org.springframework.orm.hibernate3.HibernateTransactionManager - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@86d1da]
org.hibernate.transaction.JDBCTransaction - commit
org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections
org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
org.hibernate.pretty.Printer - listing entities:
org.hibernate.pretty.Printer - com.lyl.system.entity.User{sex=null, userCode=000008, password=m123, updateDate=Wed Nov 11 22:17:04 CST 2015, tephone=13145453211, id=402883e750f6e82e0150f6e833cb0000, createUser=1, enableFlag=false, address=上海市松江区, [email protected], userName=zhangsan, createDate=Wed Nov 11 22:17:04 CST 2015, updateUser=1}
org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
org.hibernate.SQL -
insert
into
demo1_user
(createDate, createUser, enableFlag, updateDate, updateUser, address, email, password, sex, tephone, userCode, userName, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
demo1_user
(createDate, createUser, enableFlag, updateDate, updateUser, address, email, password, sex, tephone, userCode, userName, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
org.hibernate.cache.UpdateTimestampsCache - Pre-invalidating space [demo1_user]
org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
org.hibernate.cache.UpdateTimestampsCache - Invalidating space [demo1_user], timestamp: 5927941833596929
org.springframework.orm.hibernate3.HibernateTransactionManager - Closing Hibernate Session [org.hibernate.impl.SessionImpl@86d1da] after transaction
org.springframework.orm.hibernate3.SessionFactoryUtils - Closing Hibernate Session
org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!

   有上面日志可以看出,首先从spring bean工厂里面取得单例userService,进入save方法后开启事务,并打开session ,在执行到调用方法codeGenerateService.generateUserCode_REQUIRES_NEW()获取用户代码时,在codeGenerateService的方法generateUserCode_REQUIRES_NEW()时根据配置,方法内又开启了一个新事务,当generateUserCode_REQUIRES_NEW()调用完成后,将新开启的事务就提交了,因此我们可以通过try catch捕获执行运行时异常(包括数据库执行异常),如果不捕获发生的异常,导致UserService的save方法事务回滚,保存失败。

假设我们有UserService方法中,同样声明了一个生成用户代码的方法如下:

public String generateUserCode_REQUIRES_NEW(){
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("codeType", SystemEnum.CODE_TYPE.USER_CODE);
		List<CodeGenerate> codeList = baseDao.findByHQL(
				"from CodeGenerate where codeType=:codeType", paramMap);
		CodeGenerate cg = codeList.get(0);
		String value = cg.getValue();
		Integer i = Integer.valueOf(value);
		i = i + 1;
		cg.setValue(i.toString());
		baseDao.update(cg);
		Double d = new Double(Math.pow(10, 6));
		int a = d.intValue() + i;
		String str = new Integer(a).toString();
		str = str.substring(1);
		return str;
	}

 

在UserService的调用本类声明的方法generateUserCode_REQUIRES_NEW()会怎么样呢?看下面的日志就知道了。

写道
2015-11-11 10:34:36:DEBUG main org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userService'
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Creating new transaction with name [com.lyl.system.service.UserService.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2015-11-11 10:34:36:DEBUG main org.hibernate.impl.SessionImpl - opened session at timestamp: 5927946143420416
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Opened new Session [org.hibernate.impl.SessionImpl@86d1da] for Hibernate transaction
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@86d1da]
2015-11-11 10:34:36:DEBUG net.sf.ehcache.CacheManager@6691da net.sf.ehcache.util.UpdateChecker - Checking for update...
2015-11-11 10:34:36:DEBUG main org.hibernate.transaction.JDBCTransaction - begin
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.ConnectionManager - opening JDBC connection
2015-11-11 10:34:36:DEBUG main org.hibernate.transaction.JDBCTransaction - current autocommit status: true
2015-11-11 10:34:36:DEBUG main org.hibernate.transaction.JDBCTransaction - disabling autocommit
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8, UserName=root@localhost, MySQL Connector Java]
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
2015-11-11 10:34:36:DEBUG main org.hibernate.loader.Loader - result row: EntityKey[com.lyl.system.entity.CodeGenerate#USER_CODE]
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
2015-11-11 10:34:36:DEBUG main org.hibernate.engine.TwoPhaseLoad - resolving associations for [com.lyl.system.entity.CodeGenerate#USER_CODE]
2015-11-11 10:34:36:DEBUG main org.hibernate.engine.TwoPhaseLoad - done materializing entity [com.lyl.system.entity.CodeGenerate#USER_CODE]
2015-11-11 10:34:36:DEBUG main org.hibernate.engine.StatefulPersistenceContext - initializing non-lazy collections
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
2015-11-11 10:34:36:DEBUG main org.hibernate.event.def.AbstractSaveEventListener - generated identifier: 402883e750f6f83e0150f6f8438c0000, using strategy: org.hibernate.id.UUIDHexGenerator
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Initiating transaction commit
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@86d1da]
2015-11-11 10:34:36:DEBUG main org.hibernate.transaction.JDBCTransaction - commit
2015-11-11 10:34:36:DEBUG main org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
2015-11-11 10:34:36:DEBUG main org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections
2015-11-11 10:34:36:DEBUG main org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 1 insertions, 1 updates, 0 deletions to 2 objects
2015-11-11 10:34:36:DEBUG main org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
2015-11-11 10:34:36:DEBUG main org.hibernate.pretty.Printer - listing entities:
2015-11-11 10:34:36:DEBUG main org.hibernate.pretty.Printer - com.lyl.system.entity.User{sex=null, userCode=000010, password=m123, updateDate=Wed Nov 11 22:34:36 CST 2015, tephone=13145453211, id=402883e750f6f83e0150f6f8438c0000, createUser=1, enableFlag=false, address=上海市松江区, [email protected], userName=zhangsan, createDate=Wed Nov 11 22:34:36 CST 2015, updateUser=1}
2015-11-11 10:34:36:DEBUG main org.hibernate.pretty.Printer - com.lyl.system.entity.CodeGenerate{value=10, codeType=USER_CODE}
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2015-11-11 10:34:36:DEBUG main org.hibernate.SQL -
Hibernate:
insert
into
demo1_user
(createDate, createUser, enableFlag, updateDate, updateUser, address, email, password, sex, tephone, userCode, userName, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2015-11-11 10:34:36:DEBUG main org.hibernate.cache.UpdateTimestampsCache - Pre-invalidating space [demo1_user]
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2015-11-11 10:34:36:DEBUG main org.hibernate.SQL -

Hibernate:
update
demo1_code_generate
set
value=?
where
codeType=?
2015-11-11 10:34:36:DEBUG main org.hibernate.cache.UpdateTimestampsCache - Pre-invalidating space [demo1_code_generate]
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
2015-11-11 10:34:36:DEBUG main org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
2015-11-11 10:34:36:DEBUG main org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
2015-11-11 10:34:36:DEBUG main org.hibernate.cache.UpdateTimestampsCache - Invalidating space [demo1_code_generate], timestamp: 5927946145214465
2015-11-11 10:34:36:DEBUG main org.hibernate.cache.UpdateTimestampsCache - Invalidating space [demo1_user], timestamp: 5927946145214465
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.HibernateTransactionManager - Closing Hibernate Session [org.hibernate.impl.SessionImpl@86d1da] after transaction
2015-11-11 10:34:36:DEBUG main org.springframework.orm.hibernate3.SessionFactoryUtils - Closing Hibernate Session
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
2015-11-11 10:34:36:DEBUG main org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!

 

 UserService调用用本类中的EQUIRES_NEW结尾的方法并没有 开启事务,也就是说时它们属于同一个事务,而且执行是顺序我我们注意到打印save中的insert语句,再打印generateUserCode_REQUIRES_NEW()方法的update语句,说明调用方法比被调方法中的(影响数据)语句先执行。

总结:

当我们需要保证执行某个操作时单独事务的时候,需要注意两点:

1、首先需要在配置文件中声明那些需要启用新事务REQUIRES_NEW

2、调用方法和被调用需要开启新事务的方法不在同一个类中。(类中的A方法不能调用同类中B方法,即使B方法已经声明需要开启新事务)。

 

    

猜你喜欢

转载自liuyunlong1229.iteye.com/blog/2256531