事务,是在数据库中用于保证数据正确性的一种机制,涉及到很多概念以及不同的情况,这里做一个总结
相关概念
事务四特性(ACID)
原子性(Atomicity,或称不可分割性):要么全部完成或者全部不完成,错误是会发生回滚,这个要求两条相关的操作,就像情侣一样,要么一起海誓山盟,一个发生意外,另外一个也挂了
一致性(Consistency):操作完成后和原本想的结果一样,不能对数据完整性造成破坏
隔离性(Isolation,又称独立性):可以同时开启多个事务,为避免出现错误,针对这个问题制定了事务在处理时对数据进行不同隔离
持久性(Durability):事务操作后数据永久存储数据库。
事务并发问题
脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据,数据是错误的就是脏数据
不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
幻读:一个事务进行数据处理,正在处理时插入一条记录,原本事务处理后发现一条记录没有更改,如同发生幻觉一般。
spring事务机制
spring针对事务进行一系列的处理
事务隔离级别
在多个事务进行处理的时候锁住数据,保证统一时间只有一个事务对数据进行处理,针对不同的情况有不同的锁
DEFAULT(默认值):使用底层数据库事务隔离级别,MySql中使用select @@tx_isolation可以查询当前隔离级别
READ_COMMITTED:读已提交,读到已经提交的数据,可以防止脏读,但是对不可重复读和幻读
READ_UNCOMMITTED:读未提交,可以读取没有提交的数据,较少用
REPEATABLE_READ:重复读取,读出去后自动加锁,其他事务不能修改,解决脏读,不可重复读
SERIALIZABLE:串行化,事务一个排一个执行,一个事务执行完成后执行下一个
事务传播机制
在服务中进行数据库操作,两个操作中事务如何管理
REQUIRED(默认值):如果当前没有事务开启一个事务,有的话自动加入到这个事务中
REQUIRES_NEW :针对被调用者,不管调用者是否存在事务,被调用者创建一个新事务。
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
NESTED:如果存在事务,嵌套事务中执行,如果没有则新建
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
事物注解方式: @Transactional
当标于类前时, 标示类中所有方法都进行事物处理 , 例子:
1 @Transactional
public class TestServiceBean implements TestService {}
当类中某些方法不需要事物时:
@Transactional
public class TestServiceBean implements TestService {
private TestDao dao;
public void setDao(TestDao dao) {
this.dao = dao;
}
@Transactional(propagation =Propagation.NOT_SUPPORTED)
public List getAll() {
return null;
}
}
@Transactional注解中常用参数说明
readOnly:
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
指定单一异常类:
@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:
@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName
该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:
指定单一异常类名称:
@Transactional(rollbackForClassName="RuntimeException")
指定多个异常类名称:
@Transactional(rollbackForClassName={"RuntimeException","Exception"})
noRollbackFor
该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:
指定单一异常类:
@Transactional(noRollbackFor=RuntimeException.class)
指定多个异常类:
@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName
该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:
指定单一异常类名称:
@Transactional(noRollbackForClassName="RuntimeException")
指定多个异常类名称:
@Transactional(noRollbackForClassName={"RuntimeException","Exception"})
propagation
该属性用于设置事务的传播行为。
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation
该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout
该属性用于设置事务的超时秒数,默认值为-1表示永不超时
Spring事务在哪些情况下失效
1.数据库引擎要支持事务,如果是MySQL,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的
2.@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
3.Service类没有被Spring管理。因为Spring的事务是基于AOP,所以如果Service类没有被Spring管理,变成一个Spring Bean,即使添加了@Transactional注解,事务也是无效的。
4.是不是同一个类中的方法调用
5.异常是不是被catch住了