数据库事务
事务特性
原子性:事务中的操作要么一起成功,要么一起失败,不会出现部分成功,部分失败的状况
一致性:事物从一个一致性状态到另一个一致性状态,如A账户给B账户转账10元,要么A、B账户不增不减,要么A减10,B加10
隔离性:指事务之间的隔离级别
持久性:事务成功提交,会永久保存,不会回滚
mysql隔离级别
读未提交:一个事务读取另一个事物未提交的数据,会导致脏读、丢失更新、不可重复读、幻读
读提交:一个事务读取另一个事务提交后的结果,提交前不可读,会导致不可重复读、幻读
可重复读(默认):同一事务中,对相同的数据结果可重复读取,mysql中解决了不可重复读、部分幻读,存在写幻读
序列化:读写操作按顺序执行,解决了并发问题,但性能较低
隔离级别实现原理
mysql使用MVCC、锁实现事务之间的隔离级别
读未提交:读写不加锁
读提交:读不加锁,每次读的时候都是读最新数据快照,写加写锁(行锁)
可重复读:读不加锁,第一次读的时候读当前快照,后续读的时候读同一个快照,写加写锁(间隙锁或者临键锁)
序列化:读加共享锁(间隙锁或者临键锁)、写加写锁(间隙锁或者临键锁)
read view
读提交:每次执行select时,都会生成一个read view(read view为全量数据)
可重复读:首次执行select时生成read view
read_view数据结构
m_ids:生成数据快照时,当前活跃的事务集合
min_trx_id:m_ids中最小的事务id
max_trx_id:数据库分配给下一个事务的id(不是m_ids中的最大值,应至少比最大值大1)
creator_trx_id:创建数据快照的事务id
数据读取规则
如果行记录的最新事务id = creator_trx_id,说明修改行记录的事务为当前事务,当前事务可以读取最新行记录;
如果行记录的最新事务id < min_trx_id,说明行记录在该事务之前就已经提交了,当前事务可以读取最新行记录;
如果行记录的最新事务id >=max_trx_id,说明修改行记录的事务在当前事务之后,且数据还未提交,当前事务不可读取最新数据记录,需根据undo log读取历史记录;
如果行记录的最新事务id介于min_trx_id、max_trx_id之间
行记录最新事务id不在活跃列表m_ids中,说明生成数据快照时行记录已经提交,当前事务可以读取最新的行记录;
行记录的最新事务id在活跃列表m_ids中,说明生成数据快照时行记录还没有提交,当前事务不可以读取最新的行记录,需根据undo log读取行记录的历史记录;
事务并发问题
脏读:一个事务读取另一个事务未提交的数据
丢失更新:一个事务的数据更新被另一个事物覆盖,导致更新丢失,如:A、B事务同时对同一数据加1,最后两个事务都提交后,数据只加了1
不可重复读:一个事务先后读同一条数据,读取的结果不一样
幻读:一个事务先后两次读,读取结果不一样
传播行为
常用传播行为
required:若调用方法有事务,则使用调用方法的事务,否则新建事务
requires_new:被调用方法新建事务执行,被调用方法发生异常时,只回滚本方法事务,不回滚调用方法事务
nested:被调用方法发生异常时,只回滚本方法事务,不回滚调用方法事务,与requires_new的区别是,如果数据库支持保存点,就在调用处使用保存点,发生异常时回滚到保存点,若不支持保存点,则新建事务执行操作