事务隔离级别
多个应用程序同时访问同一数据,数据库的数据就会在各个不同的事务中被访问,这样会产生数据丢失更新。为了压制丢失更新的产生,数据库定义了隔离级别的概念。
| 隔离级别 |
描述 |
使用场景 |
出现坏处 |
| 未提交读写(read uncommitted) |
允许一个事务读取另一个事务没有提交的数据。 |
危险的隔离级别,应用不广,适合对数据一致性没有要求而追求高并发的场景。 |
会出现脏读。(b事务读取了a事务操作后的数据,b事务提交后,a事务回滚到b事务提交后的数据。) |
| 读写提交( read committed ) |
一个事务只能读取另一个事务已经提交的数据。 |
克服脏读, |
会出现不可重复读。(库存为1时,b事务在a事务未提交扣减读取库存为1,在a事务提交之后扣减,出现扣减失败,库存对于b事务是一个可以变化的值) |
| 可重复读 |
b事务不允许读取a事务操作后未提交的数据,等待a事务提交后才能读取。 |
克服了不可重复读, |
会出现幻读。(b事务在a事务操作及提交前后两次读取的数据不一致) |
| 串行化(Serializable) |
要求所有的SQL语句都会按顺序执行 |
数据库的最高隔离级别,可以克服脏读、不可重复读、幻读等问题,保证数据一致性。 |
|
隔离级别及其会发生的现象
| 隔离级别 |
脏读 |
不可重复读 |
幻读 |
| 未提交读写 |
√ |
√ |
√ |
| 读写提交 |
× |
√ |
√ |
| 可重复读 |
× |
× |
√ |
| 串行化 |
× |
× |
× |
常用数据库对事物隔离级别的支持
| 隔离级别/ 数据库 |
未提交读写 |
读写提交 |
可重复读 |
串行化 |
| Mysql |
√ |
√ |
√(默认) |
√ |
| Oracle |
× |
√(默认) |
× |
√ |
事物传播行为
传播行为是方法直接调用事务采取的策略。如一个方法调用另一个方法时,可以让事务采取不同的策略工作:新建事务还是挂起当前事务等。
Spring 事务机制中对数据库存在7中传播行为,通过枚举ProPagation定义的。
| 枚举类型 |
关键词 |
传播行为策略 |
| REQUIRED(TransactionDefinition. PROPAGATION_REQUIRED) |
request: |
需要事务,它是默认的传播行为,如果当前存在事务就沿用当前事务,否则新建一个事务运行子方法 |
| SUPPORTS(TransactionDefinition. PROPAGATION_SUPPORTS)
|
supports: |
支持事务,如果当前存在事务就沿用当前事务,否则采用无事务方式运行子方法 |
| MANDATORY(TransactionDefinition. PROPAGATION_MANDATORY), |
mandatory: |
必须使用事务,如果当前没有事务则抛出异常,如果存在事务就沿用当前事务 |
| REQUIRES_NEW(TransactionDefinition. PROPAGATION_REQUIRES_NEW), |
request_new:
|
无论是否存在事务都会创建新事务,这样的新事务就可以拥有新的锁和隔离级别等特性,与当前事务相互独立 |
| NOT_SUPPORTED(TransactionDefinition. PROPAGATION_NOT_SUPPORTED), |
not_supported: |
不支持事务,当前存在事务时,事挂起事务,运行方法 |
| NEVER(TransactionDefinition. PROPAGATION_NEVER), |
never: |
不支持事务,当前方法存在事务时,则抛出异常,否则无法使用无事务机制运行 |
| NESTED(TransactionDefinition. PROPAGATION_NESTED); |
nested: |
在当前方法调用子方法时,如果子方法发生异常,只回滚子方法执行过的SQL,而不是回滚当前方法的事务 |