Spring 大家再熟悉不过啦,事务这块也会经常用到,但是不经常用到的配置还有有些生疏,还是记一片文章来的直接,用的时候就来看一下,
1.Spring 事务的配置
配置好数据源之后,通过常用的两种方式: 一种是通过AOP切面的方式,另外一种为注解的方式
AOP方式
a) 配置事务管理器Bean transactionManager
b)配置AOP通知 txAdvice
c)配置AOP 切面
注解方式
2. Spring 事务传播属性 (Propagation)
Spring 提供了7种事务的传播机制,即:
PROPAGATION_REQUIRED 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
Spring事务传播是建立在两个方法相互调用时,内部方法采取的一种事务传播策略,
-------------------------------------- 例解:
PROPAGATION_REQUIRED
---------------------------------------------------------------------------------------------------------------------
当ServiceB.modthB 方法声明的事务为PROPAGATION_REQUIRED时,事务管理器就会查看serviceA.modthA是否已经有开启的事务,如果存在就用serviceA.modthA的事务,如果不存在serviceA.modthB就会为自己创建一个新事务.
PROPAGATION_REQUIRES_NEW
---------------------------------------------------------------------------------------------------------------------
当ServiceB.modthB 方法声明的事务为PROPAGATION_REQUIRES_NEW 时,事务管理器就会查看serviceA.modthA是否已经有开启的事务,如果存在就把serviceA.modthA的事务挂起,然后serviceA.modthB执行时单独创建一个事务执行,此策略对于serviceA.modthB来说不管serviceA.modthA是否存在都会新建事务
PROPAGATION_SUPPORTS
---------------------------------------------------------------------------------------------------------------------
通过上两个解释对于 PROPAGATION_SUPPORTS策略就很好理解了,当ServiceB.modthB 方法声明的事务为PROPAGATION_SUPPORTS 时,就看serviceA.modthA是否存在事务,如果存在就用serviceA.modthA的事务,如果没有就已非事务方式执行
PROPAGATION_MANDATORY
---------------------------------------------------------------------------------------------------------------------
当ServiceB.modthB 方法声明的事务为PROPAGATION_MANDATORY 时,就看serviceA.modthA是否存在事务,如果存在就用serviceA.modthA的事务,如果没有就抛出异常
PROPAGATION_NESTED
---------------------------------------------------------------------------------------------------------------------
理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,
而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。
而Nested事务的好处是他有一个savepoint
AOP的配置方式通过正则的方式来配置
注解方式
@Transactional(propagation = Propagation.REQUIRED)
3.Spring事务的隔离级别
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
什么是脏数据,脏读,不可重复读,幻觉读?
脏读: 指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,
另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一
个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
不可重复读: 指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。
那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据
可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻觉读: 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及
到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,
以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
http://www.cnblogs.com/yangy608/archive/2011/06/29/2093478.html (参考)
http://blog.csdn.net/seng3018/article/details/6690587 (参考)
AOP 方式中通过<tx:method name="*" propagation="SUPPORTS" isolation="READ_COMMITTED" read-only="true" />
isolation属性来配置
注解方式
在方法上增加 @Transactional(propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT)
4.其他属性配置
@Transactional(readOnly=true
如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;
如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持
read-only="true"表示该事务为只读事务,比如上面说的多条查询的这种情况可以使用只读事务,
由于只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。
(1)在JDBC中,指定只读事务的办法为: connection.setReadOnly(true);
(2)在Hibernate中,指定只读事务的办法为: session.setFlushMode(FlushMode.NEVER);
此时,Hibernate也会为只读事务提供Session方面的一些优化手段
(3)在Spring的Hibernate封装中,指定只读事务的办法为: bean配置文件中,prop属性增加“read-Only”
或者用注解方式@Transactional(readOnly=true)
Spring中设置只读事务是利用上面两种方式(根据实际情况)
在将事务设置成只读后,相当于将数据库设置成只读数据库,此时若要进行写的操作,会出现错误。
http://zhidao.baidu.com/link?url=Fi22I5L9Daf7tnPqIfy4RKKNHegJb7QpcRJkQ8GPRKZ1DXmoxQ_Whn1_HIvHTmiH87KmjbLWr1ruP4TQ4l0c1k3nQHpB5HqwaOR93_cdPQ3 (参考)