Spring 事务支持
1、事务基础知识
1.1 事务4大特性-ACDI
ACDI 是一个缩写,通常用于描述数据库事务的四个基本特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
(1). 原子性(Atomicity)
定义:原子性是指事务是一个不可分割的最小工作单元,事务中的所有操作要么全部成功,要么全部失败回滚。
(2). 一致性(Consistency)
定义:一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,即事务执行前后,数据库的完整性约束没有被破坏。
这些完整性约束包括实体完整性、域完整性、参照完整性、用户定义的完整性等。
- 实体完整性:确保每个表的主键值必须是唯一的,且不允许为空。
- 域完整性:确保列中的数据类型、范围和格式符合预定义的规则。
- 参照完整性:确保外键值必须对应于另一个表中的主键值,或者为空。
- 用户定义的完整性:确保用户自定义的业务规则得到遵守。
如何保证:
- 数据库系统:数据库管理系统(DBMS)内置了一系列机制来确保这些完整性约束。例如,通过索引、约束、触发器等机制来强制执行这些规则。
- 事务管理:数据库系统在事务提交前会检查所有完整性约束,如果发现任何违反约束的情况,事务将被回滚,确保数据库状态的一致性。
(3). 隔离性(Isolation)
定义:隔离性是指多个事务并发执行时,一个事务的执行不应影响其他事务的执行,每个事务都应该独立于其他事务。
(4). 持久性(Durability)
定义:持久性是指一旦事务提交,其对数据库的更改将永久保存,即使系统发生故障也不会丢失。
1.2 数据不一致问题
脏读、幻读和不可重复读是三种常见的数据不一致性问题。
(1). 脏读(Dirty Read)
定义:脏读是指一个事务读取了另一个事务未提交的数据。
示例:
事务 T1 插入了一条记录,但尚未提交。
事务 T2 读取了这条记录。
事务 T1 回滚,插入的记录被撤销。
事务 T2 读取到了一条实际上不存在的记录。
影响:事务 T2 读取到了不一致的数据,因为这条记录最终被回滚了。
(2). 不可重复读(Non-Repeatable Read)
定义:不可重复读是指在一个事务内多次读取同一数据,但由于其他事务的修改,导致读取结果不一致。
示例:
事务 T1 读取了一条记录 A。
事务 T2 修改了记录 A 并提交。
事务 T1 再次读取记录 A,发现数据已经改变。
影响:事务 T1 无法保证在同一个事务内读取到的数据是一致的。
(3). 幻读(Phantom Read)
定义:幻读是指在一个事务内多次执行同一查询,由于其他事务的插入或删除操作,导致查询结果集发生变化。
示例:
事务 T1 查询所有满足条件 X 的记录,得到结果集 R1。
事务 T2 插入了一条满足条件 X 的新记录并提交。
事务 T1 再次查询所有满足条件 X 的记录,得到结果集 R2,发现多了一条记录。
影响:事务 T1 无法保证在同一个事务内查询到的结果集是一致的。
1.2.1 解决方案
数据库通过不同的隔离级别来解决数据不一致的问题。
常见的隔离级别
- 读未提交(Read Uncommitted):允许脏读、不可重复读和幻读。性能最好,但数据一致性最差。
- 读已提交(Read Committed):防止脏读,但允许不可重复读和幻读。大多数数据库系统的默认隔离级别。
- 可重复读(Repeatable Read)防止脏读和不可重复读,但允许幻读。MySQL InnoDB 存储引擎的默认隔离级别。
- 序列化(Serializable):防止脏读、不可重复读和幻读。通过锁定整个表或使用多版本并发控制(MVCC)来实现。性能最差,但数据一致性最好。
2、spring 事务传播方式
- REQUIRED:如果存在事务,则加入该事务;否则创建一个新的事务。
- SUPPORTS:如果存在事务,则加入该事务;否则以非事务方式执行。
- MANDATORY:如果存在事务,则加入该事务;否则抛出异常。
- REQUIRES_NEW:创建一个新的事务,如果存在事务,则暂停当前事务。
- 新事物与当前事物完全隔离,互不影响。
- NOT_SUPPORTED:以非事务方式执行,如果存在事务,则暂停当前事务。
- NEVER:以非事务方式执行,如果存在事务,则抛出异常。
- NESTED:如果存在事务,则在嵌套事务内执行;否则创建一个新的事务。
- 嵌套事务可以独立于外部事务进行提交或回滚。
- 嵌套事务可以独立回滚,但外部事务的回滚会导致嵌套事务的回滚。
3、spring 事务隔离级别
spring对事物的管理,本质上是依赖数据库的,所以spring的事务隔离级别与数据库的是一致的。
多了一个default 默认级别,不同数据库的默认级别不同:
- mysql:可重复读(Repeatable Read)
- oracle:读已提交(Read Committed)
- sql server:读已提交(Read Committed)