Spring中事务声明方式:1、基于XML配置:在applicationContext.xml中对类的方法统一配置;2、注解式(@Transactional)

关于配置不细说,之前博文里有写:[url]http://angelbill3.iteye.com/blog/1896502[/url]

[color=blue]在做DEMO的时候,一度发现注解式配置不起作用,后来才发现在applicationContext.xml中少了一句话,即启动Spring注解的声明。[/color]如下:

<tx:annotation-driven transaction-manager="transactionManager" />



加上之后注解式事务就能用了。



1、注解式的方式(@Transactional注解方式)优先级要高于在applicationContext.xml中对类的方法统一配置。原因很简单,后者算是统一配置,前者是具体灵活,可单独对某个类进行配置,优先级当然要高了。



2、Spring提供的事务管理器类有很多,在使用jdbc的抽象以及ibatis支持时可用以下类:org.springframework.jdbc.datasource.DataSourceTransactionManager



3、Spring事务传播行为:


[table]


|propagation|说明


|REQUIRED|如果有事务,那么加入事务,没有的话新创建一个


|NOT_SUPPORTED|这个方法不开启事务


|REQUIREDS_NEW|不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务


|MANDATORY|必须在一个已有的事务中执行,否则抛出异常


|NEVER|不能在一个事务中执行,就是当前必须没有事务,否则抛出异常


|SUPPORTS|其他bean调用这个方法,如果在其他bean中声明了事务,就是用事务。没有声明,就不用事务。


|NESTED|如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动的事务,则按照REQUIRED属性执行,它使用一个单独的事务。这个事务拥有多个回滚的保存点,内部事务的回滚不会对外部事务造成影响,它只对DataSource TransactionManager事务管理器起效。


[/table]



另还可以设:


readOnly=true(只读事务),rollbackFor = ApplicationException.class(对具体的异常进行设置),timeout=30(超时时间),isolation=Isolation.DEFAULT(数据库隔离级别设置)等



4、下面重点就常用的几个用注解的方试写下实例


框架:Spring mvc + mybatis3



[color=blue][b]4.1 REQUIRED:最常用的事务传播[/b][/color]



//ServiveA
@Transactional (propagation = Propagation.REQUIRED ) 
public void dealA(){
	Article a = new Article();
	a.setTitlename("1");
	this.sql.insert("com.faj.dao.ArticleMapper.insert",a);//插入

	serviceB.dealB();//调用另一个Service方法
}

//ServiceB
@Transactional (propagation = Propagation.REQUIRED ) 
public void dealB(){
	Article a = new Article();
	a.setTitlename("3");
	this.sqlSession.insert("com.faj.dao.ArticleMapper.insert",a);
    throw new ApplicationException();
    //ApplicationException是一个继承RunTimeExcepiotn的异常处理类
}




//运行结果分析:-------------------------------------


(列举主要步骤)


[color=red][b]以下信息是在LOG4J的DEBUG级别层打印。[/b][/color]



[DEBUG] 2013-09-09 17:06:33 :Creating new transaction with name [com.service.impl.ServiceAImpl.dealA]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[DEBUG] 2013-09-09 17:06:33 :Creating a new SqlSession
[DEBUG] 2013-09-09 17:06:33 :Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@54fe9ab3]
[DEBUG] 2013-09-09 17:06:33 :==>  Preparing: insert into article (id, titlename, type, insertuser, inserttime, state, updateuser, updatetime, isdelete, indeximg, indexcontent, readcount, commit, support, content ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 

[DEBUG] 2013-09-09 17:06:33 :Participating in existing transaction 
[DEBUG] 2013-09-09 17:06:33 :Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@54fe9ab3] from current transaction
[DEBUG] 2013-09-09 17:06:33 :==>  Preparing: insert into article (id, titlename, type, insertuser, inserttime, state, updateuser, updatetime, isdelete, indeximg, indexcontent, readcount, commit, support, content ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 

[DEBUG] 2013-09-09 17:17:30 :Participating transaction failed - marking existing transaction as rollback-only
[DEBUG] 2013-09-09 17:17:30 :Setting JDBC transaction [com.mysql.jdbc.Connection@6aa0328b] rollback-only
[DEBUG] 2013-09-09 17:17:30 :Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@54fe9ab3]




第1行说明新建了事务,传播行为:PROPAGATION_REQUIRED


建立一个SqlSession(54fe9ab3)


第4行:类ServiceA的dealA方法中有insert方法,所以插入数据。


接着就是释放了联连。(此步骤略)



接下来就到了运行:serviceB.dealB();//调用另一个Service方法


[b]因为事务的传播行为是PROPAGATION_REQUIRED(如果有事务,那么加入事务,没有的话新创建一个)[/b]


第6行:所以看出已经加入了已有的事务中了。(Participating in existing transaction)


第8行:类ServiceB的dealB方法中有insert方法,所以插入数据,[b]可以看出是同一个SESSIONID。[/b]


第10行,两个方法共享一个事务,此时,已把主事务标记成了rollback-only



[b]类ServiceB的dealB方法中抛出unchecked异常。[/b]


注:RunTimeException属于unchecked异常,若抛出Exception(属checked异常),不会回滚。


所以在第12行,事务回滚。



[b]因为是共享事务,所以两条插入语句都会回滚。[/b]