什么是事务?
事务是应用程序中一系列的操作集合。所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。即多条语句放在事务中执行的时候,不能被部分的完成,它们是一个不可分割的工作单元。
事务具有ACID性质:
原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做,任何一项操作失败,都会导致整个事务失败,其他已执行的操作都会被撤销,恢复原来的状态。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不会对其有任何影响。
事务的并发问题:
当两个或两个以上的线程,同时访问同一条记录时,就存在事务并发问题,可能造成数据混乱。解决事务并发问题,需要采用事务隔离级别来进行
脏读 | 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的就是脏数据。 |
幻读 | 事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。 |
不可重复读 | 事务A对数据库的数据进行批量操作。事务B完成记录的添加,这时新加的记录可能就没有进行事务A的批量操作。这就是幻读。 |
事务的4种隔离级别:
读未提交 READ UNCOMMITTED | 允许TransactionA读取TransactionB未提交的修改。 | √ 脏读 √ 幻读 √ 不可重复读 |
读已提交 READ COMMITTED | 要求TransactionA只能读取TransactionB已提交的修改。 | 脏读 √ 幻读 √ 不可重复读 |
可重复读 REPEATABLE READ | 确保TransactionA可以多次从一个字段中读取到相同的值,即TransactionA执行期间禁止其它事务对这个字段进行更新。 | 脏读 幻读 √ 不可重复读 |
串行化 SERIALIZABLE | 确保TransactionA可以多次从一个表中读取到相同的行,在TransactionA执行期间,禁止其它 事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。 | 脏读 幻读 不可重复读 |
事务的传播行为
事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的行为。
在Spring中 @Transactional 注解的 propagation 属性,用于定义事务传播行为@Transactional( propagation = Propagation.REQUIRED)
Propagation.REQUIRED | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值,也是最常见的。 |
Propagation.REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
Propagation.SUPPORTS | 如果当前存在事务 ,则加入该事务;如果当前没有事务,则以非事务方式继续运行。 |
Propagation.NOT_SUPPORTS | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
Propagation.NEVER | 以非事务的方式运行,如果当前存在事务,则抛出异常。 |
Propagation.MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
Propagation.NESTED | 如果当前事务存在,则执行嵌套事务,否则执行类似REQUIRED的操作。 |