MySQL事务隔离级别

    技术2022-07-11  82

    不积跬步,无以至千里;不积小流,无以成江海

    文章目录

    事务的概念事务的组成事务的相关特性事务的特性事务并发异常事务的隔离级别MySQL事务隔离级别演示演示-----读未提交脏读不可重复读幻读 演示-----读已提交脏读不可重复读幻读 演示-----可重复读脏读不可重复读幻读 演示-----可串行化

    事务的概念

    数据库事务是访问并可能更新数据库中各种数据项的一个程序执行单元

    事务的组成

    一个数据库事务通常包含对数据库进行读或写的一个操作序列 一个典型的数据库事务: BEGIN TRANSACTION //事务开始 SQL1 SQL2 COMMIT/ROLLBACK //事务提交或回滚

    事务的相关特性

    数据库事务可以包含一个或多个数据库操作,但这些操作构成一个逻辑上的整体。构成逻辑整体的这些数据库操作,要么全部执行成功,要么全部执行不成功。构成事务的所有操作,要么全都对数据库产生影响,要么全都不产生影响,即不管事务是否执行成功,数据库总能保持一致性状态。以上即使在数据库出现故障以及并发事务存在的情况下依然成立。

    事务的特性

    原子性(Atomicity)

    事务中的所有操作作为一个整体像原子一样不可分割,要么全部成功,要么全部失败。

    一致性(Consistency)

    事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态。

    隔离性(Isolation)

    并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。

    持久性(durability)

    事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会导致数据丢失。

    事务并发异常

    丢失更新 指事务覆盖了其他事务对数据的已提交修改,导致其他事务的修改好像丢失了一样

    脏读 指一个事务读取了另一个事务未提交的数据

    幻读 指事务读取某个范围的数据时,因为其他事务的操作导致前后两次读取的结果不一致

    不可重复读 指一个事务对同一数据的读取结果前后不一致

    事务的隔离级别

    概念:事务并发操作同一批数据的时候所导致的问题可以通过设置隔离级别来解决。

    隔离级别的分类(由低到高)

    读未提交(READ UNCOMMITTED)读已提交 (READ COMMITTED) – Oracle默认级别可重复度(REPEATABLE READ) – MySQL默认级别串行化(SERIALIZABLE)

    隔离级别从小到大安全性越来越高,但是效率越来越低

    丢失更新

    如果多个线程操作,基于同一个查询结构对表中的记录进行修改,那么后修改的记录将会覆盖前面修改的记录,前面的修改就丢失掉了,这就叫做更新丢失。

    解决办法

    MySQL事务隔离级别演示

    创建account表 CREATE TABLEaccount(idint(11) NOT NULL AUTO_INCREMENT,namevarchar(32) COLLATE utf8_bin DEFAULT NULL,balancedouble DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

    初始化数据

    演示-----读未提交

    脏读

    开启命令界面 查询MySQL版本 查看当前事务隔离级别 设置当前隔离级别为读未提交 开启另一个命令界面,同样查看隔离级别并设置为读未提交 分别在两个命令界面查询id为1的记录,name为张三的余额都为1000,并开启事务。 此时在命令界面A修改余额为500,并查询结果。 然后在命令界面B查询id为1的结果也为500,此时说明在事务A并未提交的情况下出现了脏数据,说明在读未提交的隔离级别下会发生脏读问题。

    不可重复读

    同时在命令界面A、B开始事务。 命令界面A查询张三的余额为1000 命令界面B查询张三的余额也为1000 在命令界面A设置余额为900,并提交事务 最后在命令界面B再次查询结果为900,这时在同一个事务中两次查询的结果不一致,说明在读未提交下会出现不可重复读问题。

    幻读

    同时在命令界面A、B开始事务。 命令界面A查询总余额为2900 在命令界面B新增一个名为赵六的账户,并设置余额为1000,提交事务 提交成功后在命令界面A中查询总余额,此时结果为3900,跟之前的总余额不一样了,这就是属于两次统计总余额发生不一致,前面的统计就像是虚幻的一样。说明在读未提交下会出现幻读的问题。

    演示-----读已提交

    脏读

    打开两个命令界面A、B,分别设置事务隔离级别为读已提交,并开启事务。 首先在界面A查看id为1的余额为1000,然后修改余额为900,不提交事务。 然后,在界面B中查看id为1的余额为1000,此时读取到仍然是A事务修改之前的内容,这就说明读已提交不存在脏读的问题。

    不可重复读

    在命令界面A、B中分别开启事务 首先在界面A查询id为1的余额为1000 然后,在界面B修改id为1的余额为800,并提交事务 最后,在界面A再次查看id为1的余额变为了800,此时说明在读已提交的隔离级别下依旧存在不可重复读的问题。

    幻读

    同时在命令界面A、B开始事务。 命令界面A查询总余额为3800 在命令界面B新增一条数据,并设置余额为1000,提交事务 提交成功后在命令界面A中查询总余额,此时结果为4800,跟之前的总余额不一样了,这就说明读已提交下依旧存在幻读的问题。

    演示-----可重复读

    脏读

    分别在命令界面A、B设置隔离级别为可重复度,并开启事务。首先在界面A查询id为1的余额为800,然后修改余额为1000,最后在界面B查询的结果为事务A修改前的结果,说明脏读在可重复读的隔离级别下不存在。

    不可重复读

    分别在命令界面A、B开启事务。首先在界面A查询id为1的余额为1000,然后在界面B修改余额为500并提交事务,最后在界面A查询id为1的结果依然为1000,说明不可重复读在可重复读的隔离级别下不存在。 界面A: 界面B:

    幻读

    分别在命令界面A、B开启事务。首先在界面A查询总余额为4500,然后在界面B添加一条余额为1000的记录并提交事务,之后在界面A再次查询总余额结果依然为4500,此时,并没有出现幻读的情况,理论上可重重复读的隔离级别是不能防幻读的,但是因为,可重复读会对读的行来加锁,导致其他的事务修改不了这条数据,直到这个事务结束。但是,这种方案只能锁住数据行,也就是说如果有新的数据进来是阻止不了的,这也就是产生幻读的原因。但是,像MySQL、Oracle等这些成熟的数据库,它们不会采用这种影响性能的方案,所以在可重复读的这种隔离级别下就已经解决了幻读出现的问题。

    演示-----可串行化

    一旦设置隔离级别为可串行化,所有的异常都不会出现,但是它的效率最低,不推荐使用。

    Processed: 0.014, SQL: 9