Mysql的事务特性、隔离、事务传播
ACID原则
事务的原子性(Atomicity)
是指一个事务要么全部执行,要么不执行,也就是说一个事务不可能只执行了一半就停止了。比如你从取款机取钱,这个事务可以分成两个步骤:1划卡,2出钱。不可能划了卡,而钱却没出来。这两步必须同时完成,要么就不完成。
事务的一致性(Consistency):
是指事务的运行并不改变数据库中数据的一致性。例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变。
独立性(Isolation):
事务的独立性也有称作隔离性,是指两个以上的事务不会出现交错执行的状态。因为这样可能会导致数据不一致。
持久性(Durability):
事务的持久性是指事务执行成功以后,该事务对数据库所作的更改便是持久的保存在数据库之中,不会无缘无故的回滚。
4种事务隔离级别
我来总结下这三种异常情况的特点:
脏读:读到了其他事务还没有提交的数据。
不可重复读:对某数据进行读取,发现两次读取的结果不同,也就是说没有读到相同的内容。这是因为有其他事务对这个数据同时进行了修改或删除。
幻读:事务 A 根据条件查询得到了 N 条数据,但此时事务 B 更改或者增加了 M 条符合事务 A 查询条件的数据,这样当事务 A 再次进行查询的时候发现会有 N+M 条数据,产生了幻读。
Read uncommitted
一个事务可以读取另一个未提交事务的数据
Read committed
一个事务要等另一个事务提交后才能读取数据
Repeatable read (Mysql默认)
开始读取数据(事务开启)时,不再允许修改操作(Update)
Serializable 序列化
Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。
事务传播行为
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { //调用时将事务B加入事务A
methodB();
// do something
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// do something
}
PROPAGATION_SUPPORTS
如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { //调用时将事务B加入事务A
methodB();
// do something
}
// 事务属性为SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() { //单独运行时不使用事务
// do something
}
PROPAGATION_MANDATORY
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { //调用时将事务B加入事务A
methodB();
// do something
}
// 事务属性为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() { //单独运行时抛出异常
// do something
PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。(挂起事务A、事务A、B独立)
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { //调用时将事务B加入事务A
//事务A挂起............
methodB(); //事务B开始进行
//事务A继续.......
// do something
}
// 事务属性为REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// do something
PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。(methodB 非事务运行、挂起事务A、事务独立)
使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚。与PROPAGATION_REQUIRES_NEW相似但又有本质区别