# 聊聊数据库事物处理

## 1. 事物的4个基本特新

1. 原子性
2. 一致性
3. 隔离性
4. 持久性

## 2. 事物的隔离级别

1. 场景：并发修改提交，脏数据
2. 并发安全和性能互斥

隔离级别，由低到高的顺序是：

1. 未提交读
2. 读写提交
3. 可重复读
4. 串行话

* 未提交读：一个事物可以读取到另一个事物没有提交的数据，出现脏读。危险，不使用。
* 读写提交：一个事物只能读取另一个事物提交的数据，不能读取未提交的数据。不可重复读。
* 可重复读：一个事物等待另一个事物提交后再读取。行锁。容易出现幻读。
* 串行化：最高隔离级别，sql顺序执行，克服各种问题，保证数据的一致性。

现实中，隔离级别以读写提交为主，可以防止脏读，不能避免不可重复读和幻读。

为了克服数据不一致和性能问题，不再使用数据库而使用其他手段，redis分布式锁

## 3. 传播行为

传播行为是方法之间调用事物采用的策略，绝大部份情况下，我们认为数据库事物要么全部成功，要么全部失败。

一个方法调用另一个方法，涉及到传播行为。这些设置都是设置在另一个方法上的

1. **`required`**(常用): 需要事物，默认的传播行为，如果当前存在事物就沿用当前的事物，否则新建一个事物运行子方法
2. supports: 支持事物，如果当前存在事物，就沿用当前的事物，如果不存在，就继续采用无事物的方式运行子方法
3. mandatory: 必须使用事物，如果当前没有事物就抛出异常，如果存在当前事物，就沿用当前事物
4. **`requires_new`**(常用): 无论当前事物是否存在，都会创建新事物运行方法
5. not\_supported: 不支持事物，当前存在事物，将事物挂起运行方法
6. never: 不支持事物，如果当前存在事物，就抛出异常，否则继续使用无事物机制运行
7. **`nested`**(常用): 子方法发生异常，只会滚子方法执行过的sql，不回滚当前方法的事物

## 4. 自调用失效问题

同一个service中的两个方法，相互调用，事物失效

解决方法：

1. 避免同一个serivce方法相互调用
2. applicationcontext.getBean(UserService.class);获取bean，调用方法。
