MySQL 事务
保证多个任务执行要不同时成功要不同时回滚。事务支持是在引擎层实现的,Mysql 的默认引擎 InnoDB 是支持事务的,MyISAM 是不支持事务的。
事务特性 ACID
- 原子性:一个事务包括多个任务,所有的任务要不全成功,要不全部失败回滚,不存在部分成功;
- 一致性:如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态;如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态;
- 隔离性:指在并发环境中,并发的事务是相互隔离的,每个事务都有各自完成的数据空间,一个事务的执行不能不被其他事务干扰;
- 持久性:事务一旦提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。
ACID 保证
- 原子性:MySQL 使用 undo log 实现原子性。undo log 实际上是事务操作的反向操作日志,一旦发送异常回滚,将执行 undo log;
- 持久性:持久性是由 内存 + redo log 来保证的,MySQL 的 InnoDB 在修改数据的时候,同时在内存和 redo log 记录这次操作,宕机的时候可以从redo log 中恢复数据;
- 隔离性:在MySQL中隔离性是通过MVCC多版本并发控制机制来保证的;
- 一致性:只需要保证原子性、隔离性、持久性和程序一致性处理,自然也就保证了数据的一致性。
隔离机制
事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。事务的隔离级别总共有四个:
- 读未提交:在并发事务中,某个事务可以查看到其他事务未提交的数据;
- 读已提交:在并发事务中,某个事务可以看到其他事务已经修改的数据;
- 可重复读:在并发事务中,不管其他的事务怎么修改,某个事务读到的就是它刚开始读的值,这是 MySQL 的 Innodb 默认隔离级别;
- 序列化:事务序列化执行,某个时刻只有一个事务执行,该隔离级别最高最安全。
读未提交、读已提交、可重复读、序列化,从左到右隔离级别越来越高,当然性能是越来越低。
读未提交
说明:在并发事务中,某个事务可以查看到其他事务未提交的数据。以下例子:事务B并未提交,在事务A中可以看到事务B的操作结果。
问题:如果事务 B 发生异常进行回滚,那么将导致事务 A 查询的数据错误,称为脏数据,也叫脏读。
读已提交
说明:在并发事务中,某个事务可以看到其他事务已经修改的数据;以下例子:事务B未提交,事务A无法看到事务B的修改;当事务B提交后,事务A可以看到事务B的修改。
问题:在不同的时刻,查询出来的数据可能是不一致的。虽然读提交解决了脏读问题,但是无法做到可重复读(每次读的数据一致)。
可重复读
说明:在并发事务中,某个事务读到的就是它刚开始读的值,不管其他的事务怎么修改。
问题:虽然解决了可重复读问题,但是可能出现幻读。关于幻读可以查看以下例子:
注意:name是唯一键。
序列化
事务序列化执行,某个时刻只有一个事务执行。以下例子:事务A未提交,事务B无提交;当事务A提交后,事务B立即返回。
问题:序列化可以避免脏读、不可重复读、幻读,但是性能低。