前言
本文记录MySQL事务隔离级别的相关知识,包括四种隔离级别,默认级别,不同存储引擎采用的锁。
事务定义
事务是由一组sql语句组成的逻辑处理单元,具有ACID的属性
- Atomicity(原子性):一個事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
- Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
- Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
事务的隔离级别
事务a和事务b之间有一定的隔离性
隔离性有隔离级别(4个):
- 读未提交 read uncommitted
- 读已提交 read committed
- 可重复读 repeatable
- 串行化 serializable
隔离级别递增
read uncommitted 最低级别的隔离,a事务未提交的数据事务b可以读取到(脏读),一般理论存在
数据库默认的隔离级别一般高于此。读取的是内存里的数据
read committed 事务a提交的数据事务b才能读取到,可避免脏读,但是导致不可重复读取(事务b每次读取事务a的数据都不同,因为a提交了新的数据)不符合隔离性,读取的是硬盘里的数据。oracle默认的隔离级别。
repeatable:可重复读取,事务a提交了,事务b仍然读取不到。事务b可重复读取数据(每次拿到的都是事务a提交前的数据),b读取的是内存里自己存的a的数据。MySQL默认的隔离级别。会导致幻象读(事务结束后再次读取会有很大差异)
MVCC(多版本并发控制)机制:可重复读的隔离级别下使用了MVCC机制,select不会更新版本号,是快照读(自己内存里的数据),但所有更新操作会更新版本号,是当前读。
serializable:事务a在操作表中数据的时候,事务b只能等待。很少使用,吞吐量太低。
解决幻读问题:java代码同步并发、mysql间隙锁:通过where条件给表中的多条数据添加行锁,即使这条数据还不存在,也会加锁,这样操作,则其他session不能更新这几条数据,当前session读取出的数据一定是真实的。
MySQL 锁
乐观锁:用版本对比实现数据更新,如果一个线程更新一个数据时发现此时的版本和自己查询到的版本不同(即该数据已经被其他线程更新过了)则更新失败。线程更新数据成功会增加数据的版本。
悲观锁:只允许一个线程访问数据。
表锁(对一张表加锁,分读和写锁,偏读):
MYISAM采用表锁,不支持事务
加读锁:当前session和其他session都可以读这张表,当前session中插入或更新表会报错,其他session更新数据会被阻塞。(即不让任何session在当前session读取完表之前更改)
加写锁:当前session可进行任何操作,其他session全部阻塞。(即当前session更新完毕前不让任何其他session访问该表)
MYISAM 会在执行select时给对应表加读锁,在更改前加写锁。
行锁(对一行数据加锁,偏写):
InnoDB采用行锁,支持事务。
在当前session更新一行数据,如果没有提交,则此时其他session不能更新这条数据,会阻塞。只有这个session的事务commit之后,才能更新。
