简介
-
事务是要保证一组数据库操作,要么全成功,要么全失败。
-
在MySQL中,事务支持是在引擎层实现的
-
MySQL原生的MyISAM引擎是不支持事务的,InnoDB是支持事务的
-
事务的特性ACID
- Atomicity:原子性
- Consistency:一致性
- Isolation:隔离性
- Durability:持久性
隔离性
三类问题
1. 脏读:读到了未提交的数据
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
2. 不可重复读:前后多次读取,数据内容不一致
是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。(即不能读到相同的数据内容)
3. 幻读:前后多次读取,数据总量不一致
在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。
MySQL、ORACLE、PostgreSQL等成熟的数据库,出于性能考虑,都是使用了以乐观锁为理论基础的MVCC(多版本并发控制)来实现。
数据库事务隔离级别
首先要明确一点,隔离的越严实,效率就越低。因此很多时候是要在二者之间找平衡点
1. 读未提交(read uncommitted)
一个事务还没提交时,它做的变更就能被别的事务看到
2. 读提交(read committed)
一个事务提交时,它做的变更才能被其他事务看到
3. 可重复读(repeatable read)
一个事务执行过程中看到的数据,总是和这个事务在启动时看到的数据是一致的。当然在可重复读的隔离级别下,未提交变更对其他事务也是不可见的
4. 串行化(serializable)
对于同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成才能继续执行
总结
-
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在可重复读隔离级别下,这个视图是在事务启动的时候创建的,在整个事务期间都在用这个视图。读提交隔离级别下,这个视图在每个SQL语句执行时创建的。读未提交直接返回记录上的最新值,没有视图的概念。串行化直接用加锁的方式来避免并行访问
-
Oracle数据库的默认隔离级别是读提交,因此一些从Oracle迁移到MySQL的应用,为了保证数据库隔离级别的一致性,要讲MySQL的隔离级别设置为读提交
-
MySQL的默认隔离级别是可重复读,可以用select @@global.tx_isolation;查看
-
四种隔离级别和三种问题