mysql事务(ACID,脏读,不可重复读,幻读,隔离级别)
何为事务?事务是执行某个任务时的一系列操作,是一组SQL语句,多条SQL的集合。
一、事务的基本要素(ACID)
1、原子性(Atomicity):
原子,是物质构成的基本单位,不可分割,也就是说事务是一个不可分割的整体。事务里面的SQL要么全执行,要么全不执行,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。
例子:就拿A与B转账为例,一条语句从A里扣钱,另一条语句往B身上加钱,如果这两条语句不能全部执行,而是成功了一部分,那事务就没有存在的意义了。
2、一致性(Consistency):
事务开始前和结束后,数据库的一致性约束没有被破坏 。
例子:比如A向B转账100元,而余额里面只有90元,B已经收到钱,A开始扣钱,发现钱不够,然后事务需要回滚,这是原子性!!!!(要么全部执行—转账成功一加一减,要么全部失败—转账失败,金额不变)。所以不管是成功,还是失败,数据都是一致的,什么意思呢?转账成功,A减了钱,B加了钱,数据一致。转账失败,A和B的钱都没变化,数据一致。A减了钱,B却没收到,或者A没减钱,B收到了,那数据就是不一致了。
一致性其实是由原子性(执行成功,执行失败数据一致),隔离性(其他事务不会影响数据一致),持久性(需要数据持久化)决定的,也就是C是由AID做基础的,保证了数据的一致性。
3、隔离性(Isolation):
同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。
例子:A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。再比如A用户读取订单列表的时候,B用户操作,把某条订单给删了,就造成了脏读,A读的数据是错误的。
4、持久性(Durability):
事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。数据到物理存储中,已经持久化,所以有持久性。
二、事务的并发问题
1、脏读(Dirty Reads)
读取了未提交的数据:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
例子:B修改了订单详情,还未提交事务,A查看详情(读的是B修改后的数据),此时B事务出错,进行回滚。A查看的数据就是脏的(假数据)。
2、不可重复读(Non-Repeatable Reads)
前后多次读取,数据内容不一致:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
例子:事务A修改用户姓名,此时年龄为20,事务B修改年龄为25,等事务A修改完再查询,发现年龄由20变成了25。此时事务B回滚,A再返回页面发现年龄变回了20,多次读取,年龄20-25-20,重复读出来的数据内容不一致。
3、幻读(Phantom Read)
前后多次读取,数据内容不一致
例子:A将数据库中所有学生的成绩从具体分数重置为0,但是B就在这个时候插入了一条具体分数100的记录,当A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
三、mysql事务隔离级别
有四种隔离级别,用来解决数据库操作中产生的各种问题。 java中Connection类里面定义了对应的数字,分别是
1、读未提交(Read uncommitted)
所有事务能够读取其他事务未提交的数据,会造成脏读。因此在该种隔离级别下,造成脏读、不可重复读和幻读。
2、读已提交(Read committed)
Oracle和SQL Server默认的隔离级别②
所有事务只能读取其他事务已经提交的内容,能够彻底解决脏读的现象。但在这种隔离级别下,会出现一个事务的前后多次的查询中却返回了不同内容的数据的现象,也就是出现了不可重复读。
3、可重复读(Repeatable read)
mysql默认隔离级别④
所有事务前后多次的读取到的数据内容是不变的,也就是某个事务在执行的过程中,不允许其他事务进行update(delete也属于update范畴)操作,但允许其他事务进行add操作,造成某个事务前后多次读取到的数据总量不一致的现象,从而产生幻读。
4、可串行化(Serializable)
所有的事务就像被串起来,有秩序地执行,类似java的synchronized同步。所以他们之间不存在冲突,从而能有效地解决脏读、不可重复读和幻读的现象。但是安全和效率不能兼得,会导致大量的操作超时和锁竞争,从而大大降低数据库的性能,一般不使用这样事务隔离级别。
事务隔离级别对应图
事务隔离级别
脏读
不可重复读
幻读
读未提交(read-uncommitted)
是
是
是
不可重复读(read-committed)
否
是
是
可重复读(repeatable-read)
否
否
是
串行化(serializable)
否
否
否