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]