目录
1 四大特性ACID
- 原子性:事务执行的最小单位,定义的一个事务要么全部完成,要么全部不完成;
- 一致性:执行事务前后、多个事务对数据库都操作应该保证数据库状态是一致的;
- 隔离性:并发访问数据库时,多个事务之间不会被其他事务干扰;
- 持久性:一旦事务提交,对于数据库的改变应该是持久的,持久化了;
2 mysql事务
--手动处理事务,关闭自动提交
Set autocommit = 0
--设置保存点
savepoint p0
--标记事务
start transaction
--执行事务相关
insert XXX
insert XXX
delete XXX
--提交
commit
--要是失败就回滚回到保存点,删除保存点
rollback to p0
release p0
成功就正常执行定义的一系列事务操作,失败就执行回滚到定义的回滚位置
3 隔离级别
隔离级别是相对于事务的隔离性而言的,即多个客户端事务并发执行的时候;
3.1 脏读、幻读、不可重复读
- 脏读:假设两个事务,一个更新数据,一个读取数据,更新期间读入了数据,但是由于事故回滚了,那么读取数据的事务就对数据出现了脏读;
- 幻读:在一个事务中对数据库统一的查询操作,两次查询到的行(列)多了或者少了;
- 不可重复读:在一个事务中对同一个数据值的两次查询不一致;
3.2 四种隔离级别
隔离级别是相对于数据库生效的,该隔离级别对所有事务有效,默认是Repeatable Read;
- Read Uncommitted(读取,未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能导致脏读、幻读或不可重复读;
- Read Commited(读取,已提交):允许提交事务已经提交的数据,可以阻止脏读,但是幻读和不可重复读还是会发生;
- Repeatable Read(可重复读):对同一字段的多次读取结果都是一致的,除非事务本身自己修改。可以阻止脏读和不可重复读,幻读有可能发生;
- Serializable(可串行化):最高的隔离级别,完全服从ACID的隔离级别;所有事务排队依次执行,都不会互相干扰。
事务的隔离级别和加锁很相似,如果追求并发性,安全性就会降低,如果追求安全性,并发性就会降低;
4 思考
4.1 关于并发事务的问题
如果说强行要求所有的事务在执行的时候都串行执行,一个事务执行的时候,其他事务只能阻塞着,待这个事务执行完成(提交完成或者回滚完成)之后,其他事务才能执行的话,类似于单核CPU处理多线程任务,那么就不用考虑并发问题,但是这样做的效率极低,是不能容忍的,所以需要做事务可并发,但是并发就会带来一些问题。
4.1.1 更新丢失
两个事务并发,都对余额表进行扣款操作,由于操作的逻辑是“查余额->判断金额->更新余额”,两个事务在查询余额的时候都查询到了最初的余额,必然会导致另一个事务扣款的更新丢失。
4.1.2 脏读
两个事务并发,也是扣款操作,但是事务A在更新余额之后还有判断入账账户是不是黑名单的操作,如果这时候B读到了更新之后的余额,但是A判断是黑名单,那么就会触发回滚操作,此时B读的数据就是脏数据,不合预期。
4.1.3 不可重复读
事务并发,其中A事务中要反复进行对某数据值的100次查询,但是发现第30次读到的数据和第31次读到数据不一样,因为在这两次读的时候,有其他事务对这个数据值进行修改并提交了事务,对于A来说,这不是预期期望的,因为写事务的本事就是希望这是一个原子操作,不管中间我进行几次读,数据库返回给我的值都应该是一样的。
4.1.4 幻读
事务并发,A事务需要在事务中分两次查询成年人的数据项(age>=18),但是两次查到的行数是不一致的,因为中间有其他事务新插入成年人数据项(新插入的数据age>=18),这是不合预期的。
4.1.5 解决办法
- 更新丢失:通过加锁!更新前查询先加锁。
- 脏读、幻读、不可重复读:都是读的一致性问题,在读的过程中有其他事务修改这个数据。MySQL通过MVCC来解决;
4.2 关于事务隔离级别的思考
4.2.1 Read Uncommitted
读未提交,所有事务都可以看到其他未提交事务的执行结果,脏读、幻读、不可重复读都可能发生;
4.2.2 Read Committed
读已提交,一个事务只能读到其他事务已经提交的数据改变,解决了脏读的问题,但是可能有幻读和不可重复读的问题,因为在一个事务执行过程中,可能有其他事务提交事务,修改了数据;
4.2.3 Repeatable Read
可重复读,这是MySQL的默认事务隔离级别,确保同一事务的多次读取数据时,会看到同样的数据行,但是还是不能避免是幻读。
4.2.4 Serializable
所有事务,串行执行,毫无并发问题;
4.3 MVCC
版本并发控制(MultiVersion Concurrency Control,MVCC),MVCC的实现是通过保存数据在某一个时间点快照来实现的。也就是说不管实现时间多长,每个事务看到的数据都是一致的。