MySQL-事务
MySQL采用的是自动提交事务的模式。
如果不是非显式的开始一个事务,那么每个查询都当作一个事务执行提交操作。
可以通过设置autcommit来开启或者关闭自动提交
1.事务需要满足的条件:ACID
ACID表示原子性(atomicity),一致性(consistency),隔离性(isolation)和持久性(durability)
- 原子性:事务内的整个操作要么全部成功,要么失败回滚,不可能只执行其中的一部分操作。
- 一致性:事务提交前后必须保证数据是完全按照预想的规则进行修改的
- 隔离性:各个事务之间必须是相互隔离的,防止事务之间修改后导致数据的不一致
- 持久性:只要事务提交成功,那么数据就会永久的保存到数据库中,即便系统故障也不会丢失
2.隔离级别
2.1未提交读 read uncommitted
在这个隔离级别下,事务之间是相互可见的,也就是事务A可以读取到事务B的数据,但是当事务B发生问题回滚后,事务A就相当于读取到了一个不存在的数据。这种情况也成为脏读,除非有非常特殊的理由需要这样做,实际中都很少使用
2.2提交读(不可重复读 ) read committed
这个隔离级别下,事务之间是不可见的,一个事务只能读到另一个事务已提交的数据,也就是在一个事务开始后到结束前的操作,其他线程都是不可见的。
如果A事务读了一条数据,被B事务修改后并提交了事务,此时A事务还未完成并再次读取这条数据,那读到的会是B事务修改后的数据。
大部分数据库的默认级别都是该级别,但是 mysql不是
2.3可重复读 repeatable read
该级别保证了一个事务在多次读取的记录都是一致的,当A事务读了一条数据后,B事务对此条数据进行了修改并提交了事务,此时A事务还未完成并再次读取这条数据,那它读到的还是A事务一开始读到的数据(通过快照读实现)。但是还是无法解决另一个幻读的问题,也就是当A事务在读取某个范围内的数据时,B事务在这个范围内插入了新的数据,此时A事务再次读取的时候,就会产生幻行InnoDB 和 XtraDB 存储引擎通过多版本并发控制( MVCC,MultiversionConcurrencyControl)解决了幻读的问题。
可重复读是MySQL的默认隔离级别
2.3可串行化 serializable
该级别是最高隔离级别,它强制让事务串行执行,避免了幻读的问题。因为它会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争抢的问题。实际中也很少用到这个隔离级别,除非是必须保证数据强一致性,并不在乎性能的情况下(也就是串行化损失了并发)使用
3.死锁
在处理并发情况下,产生了两种锁–读锁和写锁。
- 读锁:读锁是共享的,可让多个事务共同读取其中的数据
- 写锁:是相互排斥的,只有一个事务写完才会允许另一个事务修改。
因此,当两个事务同时执行了一个update语句时,进行下一个update语句时候凑巧发现他们将要修改的都是对方前一句修改的内容,那么这个时候A事务等待B事务释放锁,而B事务等待A事务释放锁,就会陷入死循环,这就是死锁,必须有外部因素接入,才会打破这种情况。死锁会导致查询非常慢的情况,每个存储引擎解决死锁的方式不一样,一般来说是回滚其中的一个事务。
4.事务日志
事务日志可以帮助提高事务的效率(因为写日志时在磁盘上的一小块区域内进行的顺序IO,比随机IO快的多),使用事务日志的话,当存储引擎在修改表数据的时候,不会去直接写入磁盘,会把事务运行的语句写到日志文件中,然后再刷到磁盘。
所以在事务引擎上的每一次写操作都有两步:
- 写入日志文件中
- 再写入数据库文件中
如果已经记录到日志中还没有到数据库文件中,这时候发生了系统崩溃,在储存引擎重启时会自动恢复这部分修改的数据。