事务四大特性
事务需要通过严格的acid测试。Acid表示原子性,一致性,隔离性,持久性。
原子性(atomicity)
事务是不可分割的最小单元,对于整个事务的操作,要么全部提交成功,要么全部失败回滚。
一致性(consistency,最重要)
数据库总是从一个一致性的状态转换到另一个一致性的状态。要求几个事务并发执行的结果与串行顺序执行的结果一致。
隔离性(isolation)
通常,一个事务的修改在提交前对其它事务不可见。事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的(一个事务不会被另一个事务影响,最理想的就是等待一个事务执行完成后再执行另一个事务,但处于性能上的考虑,一般都需要事务并发执行,就要求事务执行过程中不受到并行执行的事务的影响,例如不能读取到另一个未提交(提交就是指事务执行完成)事务写入的值。)
持久性(durability)
事务提交后,其修改永久保存在数据库中(但不可能有100%持久性保证)
原子性是基础,隔离性是手段,一致性是约束条件,目的是保持持久性。
隔离级别
Mysql标准中有四种隔离级别
未提交读
没有提交的事务的修改对其它事务可见。会发生脏读(事务读取未提交的数据)
提交读
没有提交的事务的修改对其它事务不可见,提交的事务的修改对其它事务可见。会发生不可重复度(两次执行相同查询可能结果不一样)
可重复读(innoDB默认)
在同一个事务上读取相同的记录的结果是一致的。会发生幻读(一个事务前后两次查询相同范围,后一次查询看到了前一次查询没有看到的行,原因是另一个事务中间插入了新的记录),innoDB和xtradb存储引擎通过了多版本并发控制(MVCC,multiversion concurrency control)解决了幻读问题
可串行化
在读取的每一行数据上加锁。避免了幻读,但导致了大量超时和锁争用问题
从上往下隔离级别越高,效率越低,越安全
死锁
如果两个事务都获得了一把锁,双方又需要获取对方已经获得的锁,这时会发生死锁。
innoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚
死锁的产生可能与存储引擎有关
事务日志
使用事务日志,存储引擎在修改表的数据时,只要修改其内存拷贝,再把修改行为记录到硬盘上的事务日志上,在后台再慢慢地刷回到磁盘。通常称为预写式日志(wal,write-ahead logging),先写入日志,再写入磁盘,修改数据需要写两次磁盘。
事务只要能记录到日志并持久化成功,系统崩溃也不会丢失
Mysql的事务
Mysql有两种事务型存储引擎innoDB,NDB Cluster。还有第三方的,如XtraDB PBXT
MySQL在开启事务时会切换到延缓操作的状态:操作并不会立刻执行,commit时才会执行并切换为自动提交状态,rollback时会将延缓操作丢弃,释放申请到的锁(关键),切换为自动提交状态。
自动提交(autocommit)
Mysql默认采用自动提交(autocommit)模式。即如果不是显示开启一个事务,每次查询默认为一个事务
Mysql服务器不管理事务,事务由存储引擎实现。在同一个事务中使用多个存储引擎是不可靠的(如果在事务中混合使用了事务型和非事务型得存储引擎,在回滚时非事务型表无法撤销,事务的最终结果不确定,难以修复),mysql事务型对非事务型表回滚时会警告,通常不会有提示
隐式和显式锁定
innoDB采用两阶段锁定协议。事务执行过程中随时可以执行锁定,只有在执行commit或者rollback时同时释放所有锁(前面描述的锁都是隐式的,innoDB会根据隔离级别在需要的时候自动加锁,也支持特定的语句进行显式锁定,但不属于sql规范,应该尽量避免)
Mysql也支持lock tables和unlock tables语句,但由服务器实现,和存储引擎无关,但并不用于事务处理,使用事务还是要使用事务型存储引擎(除了事务中禁用了autocommit,可以使用lock tables外,不要显式使用lock tables)