精华内容
下载资源
问答
  • 事物的隔离级别
    千次阅读
    2022-03-08 22:50:30

    数据库的事务隔离级别是事务特性ACID中的隔离性的解读,主要作用是提高数据库的并发性。

    一、事务的特性(ACID)

    1. 原子性:依赖于undo log(MVCC,多版本并发控制器,存储在磁盘)实现,会将原数据存储在undo log中,用于容灾。
    2. 一致性:最核心和最本质的要求,依靠于原子性、隔离性和持久性进行保证。
    3. 隔离性:依靠:锁(间隙锁),mvcc(多版本并发控制)来实现。
    4. 持久性:依赖于redo log日志来实现。

    二、数据库事务隔离级别

    数据库的事务隔离级别有四种,分别是读未提交、读已提交、可重复读、序列化,不同的隔离级别下会产生脏读、幻读、不可重复读等相关问题,因此在选择隔离级别的时候要根据应用场景来决定,使用合适的隔离级别。在实际的工作中很少做修改,一般都是使用默认的隔离级别:mysql默认为不可重复读,oracle为读已提交。

    隔离级别脏读不可重复 读幻读
    READ- UNCOMMITTED
    READ-COMMITTED×
    REPEATABLE- READ××
    SERIALIZABLE×××

    1、读未提交(READ-UNCOMMITTED

            事务的修改,即使没有提交,对其他事务也都是可见的。

            事务能够读取未提交的数据,这种情况称为脏读

    2、读已提交(READ-COMMITTED)

            事务读取已提交的数据,大多数数据库的默认隔离级别。

            当一个事务在执行过程中,数据被另外一个事务修改,造成本次事务前后读取的信息不一样,这种情况称为不可重复读

    3、可重复度(REPEATABLE-READ

            这个级别是MySQL的默认隔离级别,它解决了脏读的问题,同时也保证了同一个事务多次读取同样的记录是一致的,但这个级别还是会出现幻读的情况。

            幻读是指当一个事务A读取某一个范围的数据时,另一个事务B在这个范围插入行,A事务再次读取这个范围的数据时,会产生幻读。

    4、序列化(SERIALIZABLE )

            最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

    三、事务隔离性的实现原理

            事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。锁机制采用的是间隙锁。

    1、MVCC(多版本控制器)

            MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

            MVCC多版本并发控制指的是维持一个数据的多个版本,使得读写操作没有冲突,在数据库的读操作中分为俩种:当前读和快照读。快照读是MySQL为实现MVCC的一个非阻塞读功能。

            MVCC模块在MySQL中的具体实现是由三个隐式字段,undo日志、read view三个组件来实现的。

    1.1 三个隐式字段

            在数据库中除了我们自己创建的字段,其实表中还是存在很多隐式字段的。MVCC的实现就依赖了其中的三个隐式字段:DB_TRX_ID(事务id)、DB_ROLL_PTR(回滚指针)、DB_ROW_JD(隐式主键)。

            DB_TRX_ID:6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id。

            DB_ROLL_PTR:7字节,回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个旧版本,在第一次插入数据时DB_ROLL_PTR为空。

            DB_ROW_JD:6字节,隐藏的主键,如果数据表没有主键,那么innodb会自动生成一个6字节的row_id,如果存在主键或者唯一字段就不存在DB_ROW_JD

    1.2 undo log

            undo log被称之为回滚日志,表示在进行insert,delete,update操作的时候产生的方便回滚的日志。

            当进行insert操作的时候,产生的undo log只在事务回滚的时候需要,并且在事务提交之后可以被立刻丢弃。

            当进行update和delete操作的时候,产生的undo log日志不仅仅在事务回滚的时候需要,在快照读的时候也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除(当数据发生更新和删除操作的时候都只是设置一下老记录的deleted_bit,并不是真正的将过时的记录删除,因为为了节省磁盘空间,innodb有专门的purge线程来清除deleted_bit为true的记录,如果某个记录的deleted_id为true,并且DB_TRX_ID相对于purge线程的read view 可见,那么这条记录一定时可以被清除的)。

            undo log日志采用的是链表的方式将数据进行链接。通过DB_ROLL_PTR回滚指针指向上次修改的位置。

     记录链举例:(找的资料)

    1、假设有一个事务编号为1的事务向表中插入一条记录,那么此时行数据的状态为:

    正在上传…重新上传取消

    2、假设有第二个事务编号为2对该记录的name做出修改,改为lisi

            在事务2修改该行记录数据时,数据库会对该行加排他锁。然后把该行数据拷贝到undo log中,作为 旧记录,即在undolog中有当前行的拷贝副本。拷贝完毕后,修改该行name为lisi,并且修改隐藏字段的事务id为当前事务2的id,回滚指针指向拷贝到undolog的副本记录中。事务提交后,释放锁。

    正在上传…重新上传取消

    3、假设有第三个事务编号为3对该记录的age做了修改,改为32

            在事务3修改该行数据的时,数据库会对该行加排他锁,然后把该行数据拷贝到undolog中,作为旧纪录,发现该行记录已经有undolog了,那么最新的旧数据作为链表的表头,插在该行记录的undolog最前面,修改该行age为32岁,并且修改隐藏字段的事务id为当前事务3的id,回滚指针指向刚刚拷贝的undolog的副本记录,事务提交,释放锁。

    正在上传…重新上传取消

            从上述的一系列图中,大家可以发现,不同事务或者相同事务的对同一记录的修改,会导致该记录的undo log生成一条记录版本线性表,即链表,undolog的链首就是最新的旧记录,链尾就是最早的旧记录。

    1.3 Read View

            Read View是事务进行快照读操作的时候生产的读视图,在该事务执行快照读的那一刻,会生成一个数据系统当前的快照,记录并维护系统当前活跃事务的id,事务的id值是递增的。

            在讲可见性之前,首先要知道Read View中的三个全局属性:

    trx_list:一个数值列表,用来维护Read View生成时刻系统正活跃的事务ID

    up_limit_id:记录trx_list列表中事务ID最小的ID

    low_limit_id:Read View生成时刻系统尚未分配的下一个事务ID

    具体的比较规则如下:

    1、首先比较DB_TRX_ID < up_limit_id,如果小于,则当前事务能看到DB_TRX_ID所在的记录,如果大于等于进入下一个判断

    2、接下来判断DB_TRX_ID >= low_limit_id,如果大于等于则代表DB_TRX_ID所在的记录在Read View生成后才出现的,那么对于当前事务肯定不可见,如果小于,则进入下一步判断

    3、判断DB_TRX_ID是否在活跃事务中,如果在,则代表在Read View生成时刻,这个事务还是活跃状态,还没有commit,修改的数据,当前事务也是看不到,如果不在,则说明这个事务在Read View生成之前就已经开始commit,那么修改的结果是能够看见的。

    四、参考文件

            马士兵课程。

    更多相关内容
  • 数据库隔离级别有四种,应用《高性能mysql》一书中的说明:然后说说修改事务隔离级别的方法:1.全局修改,修改mysql.ini配置文件,在最后加上#可选参数有:READ-UNCOMMITTED,READ-COMMITTED,REPEATABLE-READ,...
  • 数据库事务隔离级别 数据库事务的隔离级别有4个,由低到高依次为 Read uncommitted:允许脏读。 Read committed: 防止脏读,最常用的隔离级别,并且是大多数数据库的默认隔离级别。 Repeatable read:可以防止脏...
  • 查看事务隔离级别 在 MySQL 中,可以通过show variables like ‘%tx_isolation%’或select @@tx_isolation;语句来查看当前事务隔离级别。 查看当前事务隔离级别的 SQL 语句和运行结果如下: mysql> show variables ...
  • 事务隔离级别:一个事务对数据库的修改与并行的另一个事务的隔离程度
  • 前言 ...我们都知道事务的几种性质,数据库中的一致性和隔离性等是实现事务的基本思想,在系统有大量的并发访问的情况下,了解和熟练应用数据库的本身的事务隔离级别,对于写出健壮性,并发处理能力强
  • 查询:默认事务隔离级别 mysql> select @@tx_isolation;当前会话的默认事务隔离级别 mysql> select @@session.tx_isolation;当前会话的默认事务隔离级别 mysql> select @@global.tx_isolation;全局的事务隔离级别
  • 老实说,事务隔离级别这个问题,无论是校招还是社招,面试官都爱问!然而目前网上很多文章,说句实在话啊,我看了后我都怀疑作者弄懂没!因为他们对可重复读(Repeatable Read)和串行化(serializable)的解析实在是看...
  • MySQL 事务隔离级别

    千次阅读 多人点赞 2021-09-07 08:35:33
    1. 理论 MySQL 中事务隔离级别一共分为四种,分别如下: ...如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供了事务之间最大限度的隔离。 REPEATABLE READ ❝ 在可

    1. 理论

    MySQL 中事务的隔离级别一共分为四种,分别如下:

    • 序列化(SERIALIZABLE)

    • 可重复读(REPEATABLE READ)

    • 提交读(READ COMMITTED)

    • 未提交读(READ UNCOMMITTED)

    四种不同的隔离级别含义分别如下:

    1. SERIALIZABLE

    如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供了事务之间最大限度的隔离。

    1. REPEATABLE READ

    在可重复读在这一隔离级别上,事务不会被看成是一个序列。不过,当前正在执行事务的变化仍然不能被外部看到,也就是说,如果用户在另外一个事务中执行同条 SELECT 语句数次,结果总是相同的。(因为正在执行的事务所产生的数据变化不能被外部看到)。

    1. READ COMMITTED

    READ COMMITTED 隔离级别的安全性比 REPEATABLE READ 隔离级别的安全性要差。处于 READ COMMITTED 级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的多个 SELECT 语句可能返回不同的结果。

    1. READ UNCOMMITTED

    READ UNCOMMITTED 提供了事务之间最小限度的隔离。除了容易产生虚幻的读操作和不能重复的读操作外,处于这个隔离级的事务可以读到其他事务还没有提交的数据,如果这个事务使用其他事务不提交的变化作为计算的基础,然后那些未提交的变化被它们的父事务撤销,这就导致了大量的数据变化。

    在 MySQL 数据库种,默认的事务隔离级别是 REPEATABLE READ

    2. SQL 实践

    接下来通过几条简单的 SQL 向读者验证上面的理论。

    2.1 查看隔离级别

    通过如下 SQL 可以查看数据库实例默认的全局隔离级别和当前 session 的隔离级别:

    MySQL8 之前使用如下命令查看 MySQL 隔离级别:

    SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
    

    查询结果如图:

    图片

    可以看到,默认的隔离级别为 REPEATABLE-READ,全局隔离级别和当前会话隔离级别皆是如此。

    MySQL8 开始,通过如下命令查看 MySQL 默认隔离级别

    SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;
    

    就是关键字变了,其他都一样。

    通过如下命令可以修改隔离级别(建议开发者在修改时修改当前 session 隔离级别即可,不用修改全局的隔离级别):

    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    

    上面这条 SQL 表示将当前 session 的数据库隔离级别设置为 READ UNCOMMITTED,设置成功后,再次查询隔离级别,发现当前 session 的隔离级别已经变了,如图1-2:

    图片

    注意,如果只是修改了当前 session 的隔离级别,则换一个 session 之后,隔离级别又会恢复到默认的隔离级别,所以我们测试时,修改当前 session 的隔离级别即可。

    2.2 READ UNCOMMITTED

    2.2.1 准备测试数据

    READ UNCOMMITTED 是最低隔离级别,这种隔离级别中存在脏读、不可重复读以及幻象读问题,所以这里我们先来看这个隔离级别,借此大家可以搞懂这三个问题到底是怎么回事。

    下面分别予以介绍。

    首先创建一个简单的表,预设两条数据,如下:

    图片

    表的数据很简单,有 javaboy 和 itboyhub 两个用户,两个人的账户各有 1000 人民币。现在模拟这两个用户之间的一个转账操作。

    注意,如果读者使用的是 Navicat 的话,不同的查询窗口就对应了不同的 session,如果读者使用了 SQLyog 的话,不同查询窗口对应同一个 session,因此如果使用 SQLyog,需要读者再开启一个新的连接,在新的连接中进行查询操作。

    2.2.2 脏读

    一个事务读到另外一个事务还没有提交的数据,称之为脏读。具体操作如下:

    1. 首先打开两个SQL操作窗口,假设分别为 A 和 B,在 A 窗口中输入如下几条 SQL (输入完成后不用执行):

    START TRANSACTION;
    UPDATE account set balance=balance+100 where name='javaboy';
    UPDATE account set balance=balance-100 where name='itboyhub';
    COMMIT;
    
    1. 在 B 窗口执行如下 SQL,修改默认的事务隔离级别为 READ UNCOMMITTED,如下:

    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    
    1. 接下来在 B 窗口中输入如下 SQL,输入完成后,首先执行第一行开启事务(注意只需要执行一行即可):

    START TRANSACTION;
    SELECT * from account;
    COMMIT;
    
    1. 接下来执行 A 窗口中的前两条 SQL,即开启事务,给 javaboy 这个账户添加 100 元。

    2. 进入到 B 窗口,执行 B 窗口的第二条查询 SQL(SELECT * from user;),结果如下:

    图片

    可以看到,A 窗口中的事务,虽然还未提交,但是 B 窗口中已经可以查询到数据的相关变化了。

    这就是脏读问题。

    2.2.3 不可重复读

    不可重复读是指一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。具体操作步骤如下(操作之前先将两个账户的钱都恢复为1000):

    1. 首先打开两个查询窗口 A 和 B ,并且将 B 的数据库事务隔离级别设置为 READ UNCOMMITTED。具体 SQL 参考上文,这里不赘述。

    2. 在 B 窗口中输入如下 SQL,然后只执行前两条 SQL 开启事务并查询 javaboy 的账户:

    START TRANSACTION;
    SELECT * from account where name='javaboy';
    COMMIT;
    

    前两条 SQL 执行结果如下:

    图片

    1. 在 A 窗口中执行如下 SQL,给 javaboy 这个账户添加 100 块钱,如下:

    START TRANSACTION;
    UPDATE account set balance=balance+100 where name='javaboy';
    COMMIT;
    

    4.再次回到 B 窗口,执行 B 窗口的第二条 SQL 查看 javaboy 的账户,结果如下:

    图片

    javaboy 的账户已经发生了变化,即前后两次查看 javaboy 账户,结果不一致,这就是不可重复读

    和脏读的区别在于,脏读是看到了其他事务未提交的数据,而不可重复读是看到了其他事务已经提交的数据(由于当前 SQL 也是在事务中,因此有可能并不想看到其他事务已经提交的数据)。

    2.2.4 幻象读

    幻象读和不可重复读非常像,看名字就是产生幻觉了。

    我举一个简单例子。

    在 A 窗口中输入如下 SQL:

    START TRANSACTION;
    insert into account(name,balance) values('zhangsan',1000);
    COMMIT;
    

    然后在 B 窗口输入如下 SQL:

    START TRANSACTION;
    SELECT * from account;
    delete from account where name='zhangsan';
    COMMIT;
    

    我们执行步骤如下:

    1. 首先执行 B 窗口的前两行,开启一个事务,同时查询数据库中的数据,此时查询到的数据只有 javaboy 和 itboyhub。

    2. 执行 A 窗口的前两行,向数据库中添加一个名为 zhangsan 的用户,注意不用提交事务。

    3. 执行 B 窗口的第二行,由于脏读问题,此时可以查询到 zhangsan 这个用户。

    4. 执行 B 窗口的第三行,去删除 name 为 zhangsan 的记录,这个时候删除就会出问题,虽然在 B 窗口中可以查询到 zhangsan,但是这条记录还没有提交,是因为脏读的原因才看到了,所以是没法删除的。此时就产生了幻觉,明明有个 zhangsan,却无法删除。

    这就是幻读

    看了上面的案例,大家应该明白了脏读不可重复读以及幻读各自是什么含义了。

    2.3 READ COMMITTED

    和 READ UNCOMMITTED 相比,READ COMMITTED 主要解决了脏读的问题,对于不可重复读和幻象读则未解决。

    将事务的隔离级别改为 READ COMMITTED 之后,重复上面关于脏读案例的测试,发现已经不存在脏读问题了;重复上面关于不可重复读案例的测试,发现不可重复读问题依然存在。

    上面那个案例不适用于幻读的测试,我们换一个幻读的测试案例。

    还是两个窗口 A 和 B,将 B 窗口的隔离级别改为 READ COMMITTED

    然后在 A 窗口输入如下测试 SQL:

    START TRANSACTION;
    insert into account(name,balance) values('zhangsan',1000);
    COMMIT;
    

    在 B 窗口输入如下测试 SQL:

    START TRANSACTION;
    SELECT * from account;
    insert into account(name,balance) values('zhangsan',1000);
    COMMIT;
    

    测试方式如下:

    1. 首先执行 B 窗口的前两行 SQL,开启事务并查询数据,此时查到的只有 javaboy 和 itboyhub 两个用户。

    2. 执行 A 窗口的前两行 SQL,插入一条记录,但是并不提交事务。

    3. 执行 B 窗口的第二行 SQL,由于现在已经没有了脏读问题,所以此时查不到 A 窗口中添加的数据。

    4. 执行 B 窗口的第三行 SQL,由于 name 字段唯一,因此这里会无法插入。此时就产生幻觉了,明明没有 zhangsan 这个用户,却无法插入 zhangsan。

    2.4 REPEATABLE READ

    和 READ COMMITTED 相比,REPEATABLE READ 进一步解决了不可重复读的问题,但是幻象读则未解决。

    REPEATABLE READ 中关于幻读的测试和上一小节基本一致,不同的是第二步中执行完插入 SQL 后记得提交事务。

    由于 REPEATABLE READ 已经解决了不可重复读,因此第二步即使提交了事务,第三步也查不到已经提交的数据,第四步继续插入就会出错。

    注意,REPEATABLE READ 也是 InnoDB 引擎的默认数据库事务隔离级别

    2.5 SERIALIZABLE

    SERIALIZABLE 提供了事务之间最大限度的隔离,在这种隔离级别中,事务一个接一个顺序的执行,不会发生脏读、不可重复读以及幻象读问题,最安全。

    如果设置当前事务隔离级别为 SERIALIZABLE,那么此时开启其他事务时,就会阻塞,必须等当前事务提交了,其他事务才能开启成功,因此前面的脏读、不可重复读以及幻象读问题这里都不会发生。

    3. 总结

    总的来说,隔离级别和脏读、不可重复读以及幻象读的对应关系如下:

    图片

    性能关系如图:

    图片

    展开全文
  • 在SQL标准中定义了四种隔离级别, 每一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。 下面简单地介绍一下四种隔离级别。 1.READ ...
  • 事务隔离级别

    2022-04-21 15:49:56
    1. 理论 MySQL 中事务隔离级别一共分为四种,分别...如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供 了事务之间最大限度的隔离。 2. REPEATABLE READ 在可重复读在这

    1. 理论

    MySQL 中事务的隔离级别一共分为四种,分别如下:
    • 序列化(SERIALIZABLE
    • 可重复读(REPEATABLE READ) (默认)
    • 提交读(READ COMMITTED
    • 未提交读(READ UNCOMMITTED
    四种不同的隔离级别含义分别如下:
    1. SERIALIZABLE
    如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供 了事务之间最大限度的隔离。
    2. REPEATABLE READ
    在可重复读在这一隔离级别上,事务不会被看成是一个序列。不过,当前正在执行事务的变化仍 然不能被外部看到,也就是说,如果用户在另外一个事务中执行同条 SELECT 语句数次,结果总 是相同的。(因为正在执行的事务所产生的数据变化不能被外部看到)。
    3. READ COMMITTED
    READ COMMITTED 隔离级别的安全性比 REPEATABLE READ 隔离级别的安全性要差。处于 READ COMMITTED 级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间, 如果其他事务修改了相应的表,那么同一个事务的多个 SELECT 语句可能返回不同的结果。
    4. READ UNCOMMITTED
    READ UNCOMMITTED 提供了事务之间最小限度的隔离。除了容易产生虚幻的读操作和不能重复 的读操作外,处于这个隔离级的事务可以读到其他事务还没有提交的数据,如果这个事务使用其 他事务不提交的变化作为计算的基础,然后那些未提交的变化被它们的父事务撤销,这就导致了 大量的数据变
    MySQL 数据库种,默认的事务隔离级别是 REPEATABLE READ

    2. SQL 实践

    接下来通过几条简单的 SQL 向读者验证上面的理论。

    2.1 查看隔离级别

    通过如下 SQL 可以查看数据库实例默认的全局隔离级别和当前 session 的隔离级别:
    MySQL8 之前使用如下命令查看 MySQL 隔离级别:
    SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
    查询结果如图:

     

    可以看到,默认的隔离级别为 REPEATABLE-READ ,全局隔离级别和当前会话隔离级别皆是如此。
    MySQL8 开始,通过如下命令查看 MySQL 默认隔离级别
    SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation; 
    就是关键字变了,其他都一样。
    通过如下命令可以修改隔离级别(建议开发者在修改时修改当前 session 隔离级别即可,不用修改全局的隔离级别):
    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    上面这条 SQL 表示将当前 session 的数据库隔离级别设置为 READ UNCOMMITTED ,设置成功后,再次查询隔离级别,发现当前 session 的隔离级别已经变了,如图 1-2

     

    注意,如果只是修改了当前 session 的隔离级别,则换一个 session 之后,隔离级别又会恢复到默认的隔离级别,所以我们测试时,修改当前 session 的隔离级别即可。

    2.2 READ UNCOMMITTED

    2.2.1 准备测试数据

    READ UNCOMMITTED 是最低隔离级别 ,这种隔离级别中存在 脏读、不可重复读以及幻象读 问题,所以这里我们先来看这个隔离级别,借此大家可以搞懂这三个问题到底是怎么回事。
    下面分别予以介绍。
    首先创建一个简单的表,预设两条数据,如下:

     

    表的数据很简单,有 javaboy itboyhub 两个用户,两个人的账户各有 1000 人民币。现在模拟这两个用户之间的一个转账操作。
    注意,如果读者使用的是 Navicat 的话,不同的查询窗口就对应了不同的 session ,如果读者使用了SQLyog 的话,不同查询窗口对应同一个 session ,因此如果使用 SQLyog ,需要读者再开启一个新的 连接,在新的连接中进行查询操作。

    2.2.2 脏读

    一个事务读到另外一个事务还没有提交的数据,称之为脏读。具体操作如下:
    1. 首先打开两个 SQL 操作窗口,假设分别为 A B ,在 A 窗口中输入如下几条 SQL (输入完成后不用执行):
    START TRANSACTION; 
    UPDATE account set balance=balance+100 where name='javaboy'; 
    UPDATE account set balance=balance-100 where name='itboyhub'; 
    COMMIT
    2. B 窗口执行如下 SQL ,修改默认的事务隔离级别为 READ UNCOMMITTED ,如下
    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    3. 接下来在 B 窗口中输入如下 SQL ,输入完成后,首先执行第一行开启事务(注意只需要执行一行即可):
    START TRANSACTION; SELECT * from account; COMMIT;
    4. 接下来执行 A 窗口中的前两条 SQL ,即开启事务,给 javaboy 这个账户添加 100 元。
    5. 进入到 B 窗口,执行 B 窗口的第二条查询 SQL SELECT * from user; ),结果如下:

     

    可以看到, A 窗口中的事务,虽然还未提交,但是 B 窗口中已经可以查询到数据的相关变化了。
    这就是 脏读 问题。

    2.2.3 不可重复读

    不可重复读是指一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。具体操作步骤如下(操作之前先将两个账户的钱都恢复为 1000 ):
    1. 首先打开两个查询窗口 A B ,并且将 B 的数据库事务隔离级别设置为 READ UNCOMMITTED 。具体 SQL 参考上文,这里不赘述。
    2. B 窗口中输入如下 SQL ,然后只执行前两条 SQL 开启事务并查询 javaboy 的账户:
    START TRANSACTION; 
    SELECT * from account where name='javaboy'; 
    COMMIT;
    前两条 SQL 执行结果如下:

     3. A 窗口中执行如下 SQL,给 javaboy 这个账户添加 100 块钱,如下:

    START TRANSACTION;
    UPDATE account set balance=balance+ 100 where name= 'javaboy' ;
    COMMIT;

    4.再次回到 B 窗口,执行 B 窗口的第二条 SQL 查看 javaboy 的账户,结果如下:

     

    javaboy 的账户已经发生了变化,即前后两次查看 javaboy 账户,结果不一致,这就是 不可重复读
    和脏读的区别在于,脏读是看到了其他事务未提交的数据,而不可重复读是看到了其他事务已经提交的数据(由于当前 SQL 也是在事务中,因此有可能并不想看到其他事务已经提交的数据)。

    2.2.4 幻象读

    查询某个范围的数据,多次查询结果不同
    我举一个简单例子。
    A 窗口中输入如下 SQL
    START TRANSACTION;
    insert into account(name,balance) values ( 'zhangsan' , 1000 );
    COMMIT;

     然后在 B 窗口输入如下 SQL

    START TRANSACTION;
    SELECT * from account;
    delete from account where name= 'zhangsan' ;
    COMMIT;
    我们执行步骤如下:
    1. 首先执行 B 窗口的前两行,开启一个事务,同时查询数据库中的数据,此时查询到的数据只有
    javaboy itboyhub
    START TRANSACTION;
    SELECT * from account where name= 'javaboy' ;
    COMMIT;
    START TRANSACTION;
    UPDATE account set balance=balance+ 100 where name= 'javaboy' ;
    COMMIT;
    START TRANSACTION;
    insert into account(name,balance) values ( 'zhangsan' , 1000 );
    COMMIT;
    START TRANSACTION;
    SELECT * from account;
    delete from account where name= 'zhangsan' ;
    COMMIT;
    2. 执行 A 窗口的前两行,向数据库中添加一个名为 zhangsan 的用户,注意不用提交事务。
    3. 执行 B 窗口的第二行,由于脏读问题,此时可以查询到 zhangsan 这个用户。
    4. 执行 B 窗口的第三行,去删除 name zhangsan 的记录,这个时候删除就会出问题,虽然在 B 窗口中可以查询到 zhangsan ,但是这条记录还没有提交,是因为脏读的原因才看到了,所以是没 法删除的。此时就产生了幻觉,明明有个 zhangsan ,却无法删除。
    这就是 幻读
    看了上面的案例,大家应该明白了 脏读 不可重复读 以及 幻读 各自是什么含义了。

    2.3 READ COMMITTED

    READ UNCOMMITTED 相比, READ COMMITTED 主要解决了脏读的问题,对于不可重复读和幻象读则未解决。
    将事务的隔离级别改为 READ COMMITTED 之后,重复上面关于脏读案例的测试,发现已经不存在脏读问题了;重复上面关于不可重复读案例的测试,发现不可重复读问题依然存在。
    上面那个案例不适用于幻读的测试,我们换一个幻读的测试案例。
    还是两个窗口 A B ,将 B 窗口的隔离级别改为 READ COMMITTED
    然后在 A 窗口输入如下测试 SQL
    START TRANSACTION; 
    insert into account(name,balance) values('zhangsan',1000); 
    COMMIT;
    B 窗口输入如下测试 SQL
    START TRANSACTION; SELECT * from account; 
    insert into account(name,balance) values('zhangsan',1000); 
    COMMIT;
    测试方式如下:
    1. 首先执行 B 窗口的前两行 SQL ,开启事务并查询数据,此时查到的只有 javaboy itboyhub
    个用户。
    2. 执行 A 窗口的前两行 SQL ,插入一条记录,但是并不提交事务。
    3. 执行 B 窗口的第二行 SQL ,由于现在已经没有了脏读问题,所以此时查不到 A 窗口中添加的数
    据。
    4. 执行 B 窗口的第三行 SQL ,由于 name 字段唯一,因此这里会无法插入。此时就产生幻觉了,明明没有 zhangsan 这个用户,却无法插入 zhangsan

    2.4 REPEATABLE READ

    READ COMMITTED 相比, REPEATABLE READ 进一步解决了不可重复读的问题,但是幻象读则未解决。
    REPEATABLE READ 中关于幻读的测试和上一小节基本一致,不同的是第二步中执行完插入 SQL 后记得提交事务。
    由于 REPEATABLE READ 已经解决了不可重复读,因此第二步即使提交了事务,第三步也查不到已经提交的数据,第四步继续插入就会出错。
    注意, REPEATABLE READ 也是 InnoDB 引擎的默认数据库事务隔离级别

    2.5 SERIALIZABLE

    SERIALIZABLE 提供了事务之间最大限度的隔离,在这种隔离级别中,事务一个接一个顺序的执行,不会发生脏读、不可重复读以及幻象读问题,最安全。
    如果设置当前事务隔离级别为 SERIALIZABLE ,那么此时开启其他事务时,就会阻塞,必须等当前事务提交了,其他事务才能开启成功,因此前面的脏读、不可重复读以及幻象读问题这里都不会发生。
    3. 总结
    总的来说,隔离级别和脏读、不可重复读以及幻象读的对应关系如下:
    隔离级别
    脏读
    不可重复读
    幻象读
    READ UNCOMMITTED
    允许
    允许
    允许
    READ COMMITED
    不允许
    允许
    允许
    REPEATABLE READ
    不允许
    不允许
    允许
    SERIALIZABLE
    不允许
    不允许
    不允许
    性能关系如图:

     

    # 查看当前会话的隔离级别
    # global 表示查看全局的隔离级别,后面的表示查看当前会话的隔离级别
    SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;
    SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
    # 先修改当前事务的隔离级别为 read uncommitted,在这种隔离级别中,可以读到别的事务未提交的数据
    SET SESSION TRANSACTION ISOLATION LEVEL	READ UNCOMMITTED;
    # read uncommitted 这种隔离级别存在三种问题:脏读、不可重复读、幻读
    # 脏读:读到了别人事务尚未提交的数据(别的事务不一定对,万一回滚了呢)
    BEGIN;
    SELECT * FROM account WHERE username='zhangsan';
    COMMIT;
    # 不可重复读:对于同一条记录,多次读取,查询的结果可能不同
    
    # 幻读:查询某个范围的数据,多次查询结果不同
    # for update 表示将当前查询涉及到的记录锁住,即将 username 为 zhangsan 的用户锁住,其他的数据库操作都不可操作该记录,必须等当前事务提交了,才可以操作
    # 即 for update 其实是一个排他锁
    
    
    
    # 修改事务的隔离级别为 read committed
    SET SESSION TRANSACTION ISOLATION LEVEL	READ COMMITTED;
    # read committed 这种隔离级别只存在两种问题:不可重复读和幻读,脏读问题在这里解决了。
    # read committed 看不到别的事务未提交的数据,所以它不存在脏读问题;但是他能看到别的事务已经提交的数据,所以它存在不可重复读的问题
    BEGIN;
    SELECT * FROM account WHERE username='zhangsan';
    COMMIT;
    
    # 这是 MySQL 默认的隔离级别,这个隔离级别中解决了事务的不可重复读和幻读问题
    SET SESSION TRANSACTION ISOLATION LEVEL	REPEATABLE READ;
    BEGIN;
    SELECT * FROM account WHERE username='zhangsan';
    COMMIT;
    # 序列化执行,事务不可以并发执行,一次只能执行一个事务,所以它不存在任何问题,但是因为它的效率比较低,所以一般不用它
    SET SESSION TRANSACTION ISOLATION LEVEL	SERIALIZABLE;
    BEGIN;
    SELECT * FROM account WHERE username='zhangsan';
    COMMIT;

    展开全文
  • 事务隔离级别(图文详解) 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行。 事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的...

    事务隔离级别(图文详解)

    什么是事务?

    事务是逻辑上的一组操作,要么都执行,要么都不执行。

    事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

    常用的事务控制语法

    - 事务开始
    begin;
    - 事务提交,提交后就会写入物理磁盘中去
    commit;
    - 事务回滚,事务提交后,无法回滚
    rollback;
    
    

    事务的四大特性(ACID)

    image-20211231191231001

    1. 原子性(atomicity) **事务是最小的执行单位,不允许分割。**事务的原子性确保动作要么全部完成,要么完全不起作用;
    2. 一致性(consistency) 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
    3. 隔离性(isolation) 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
    4. 持久性(durability) 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

    关闭mysql的事务自动提交

    SET autocommit = 0|1|ON|OFF;
    

    对取值的说明:

    值为 0 和值为 OFF:关闭事务自动提交。如果关闭自动提交,用户将会一直处于某个事务中,只有提交或回滚后才会结束当前事务,重新开始一个新事务。
    值为 1 和值为 ON:开启事务自动提交。如果开启自动提交,则每执行一条 SQL 语句,事务都会提交一次。

    数据库的隔离级别

    事务隔离级别的定义

    事务指定一个隔离级别,该隔离级别**定义一个事务必须与由其他事务进行的资源或数据更改相隔离的程度。**隔离级别从允许的并发副作用(例如,脏读或幻读的角度进行描述。

    - 查看隔离级别,8.0版本之前的,用SELECT @@tx_isolation
    select @@transaction_isolation;
    
    - 修改隔离级别
    set session transaction isolation level  READ UNCOMMITTED;
    
    

    隔离级别的分类

    **读未提交(READ-UNCOMMITTED):**A事务操作后没有执行commit提交命令,但是B事务也能察觉到A操作的数据变化,此时B重新查询,则能查询出A操作后的最新数据,但是当A事务rollback回滚后,A操作的数据其实没有变化,这时候B处的数据就变成了脏数据(容易导致脏读情形产生)

    设置隔离级别为读未提交

    - 设置隔离级别
    set session transaction isolation level    read uncommitted;
     - 查看隔离级别
    select  @@transaction_isolation;
     
    

    读已提交(不可重复读 read committed)oracle默认的隔离级别:读已提交,表示只有执行了commit命令后,才能得知数据的变化,A修改了数据,没有提交,B不会察觉到数据的变化。这样虽然会避免脏读,但是会出现,当A读取某一条数据时候,B正在对该数据进行操作(修改),但是B操作并没有结束,因此此时数据并没有发生变化,但是A在B事务提交前已经执行完了,那就会出现数据不一致现象,这种问题叫做不可重复读。

    设置隔离级别为读已提交

     - 设置隔离级别
    set session transaction isolation level    read committed;
      - 查看隔离级别
    select  @@transaction_isolation;
    
    
    

    可重复读(repeatable read mysql 的默认隔离级别)

    可重复读与不可重复读很容易搞混淆,**可重复读侧重于有没有进行行增加减少,也就是新增和删除,而不可重复读侧重于修改操作,不影响行数。**可重复读是采用锁行形式,因为是锁行,所以无法保证对行数的操作限制隔离,只能保证当前锁住的行隔离影响。

    串行化

    最可靠的事务隔离级别。“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。事务 100% 隔离,可避免脏读、不可重复读、幻读的发生。因为串行化是锁表,因此虽然隔离级别最高,但是消耗资源最大

    mysql数据库默认的事务隔离级别是可重复读(REPEATABLE-READ )

    mysql> select @@transaction_isolation;
    +-------------------------+
    | @@transaction_isolation |
    +-------------------------+
    | REPEATABLE-READ         |
    +-------------------------+
    1 row in set (0.00 sec)
    

    修改数据库的事务隔离级别为不可重复读 READ-UNCOMMITTED

    mysql> select @@transaction_isolation;
    +-------------------------+
    | @@transaction_isolation |
    +-------------------------+
    | READ-UNCOMMITTED        |
    +-------------------------+
    

    这下面是MySQL8的事务隔离级别,MySQL5的话可重读读,还是会出现幻读

    事务隔离级别脏读不可重复读幻读
    读未提交(read-uncommitted)
    不可重复读(read-committed)
    可重复读(repeatable-read)
    串行化(serializable)

    并发事务带来的问题

    在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。

    • 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,然后后一个事务进行回滚,将数据变成之前的值,那么前一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。(读取未提交数据)
    时间顺序转账事务取款事务
    1开始事务
    2开始事务
    3查询账户余额为2000元
    4取款1000元,余额被更改为1000元
    5查询账户余额为1000元(产生脏读)
    6取款操作发生未知错误,事务回滚,余额变更为2000元
    7转入2000元,余额被更改为3000元(脏读的1000+2000)
    8提交事务
    备注按照正确逻辑,此时账户余额应该为4000元

    注意:这里要修改mysql的事务隔离级别为不可重复读( READ-UNCOMMITTED )

    account表中的原始状态

    image-20211231200932520

    image-20211231201320508

    image-20211231201342895

    image-20211231201534124

    image-20211231201641543

    image-20220101115134146

    image-20220101115237036

    • 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

    • 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。(前后多次读取,数据内容不一致)

    image-20220101144933767

    image-20220101150808461

    image-20220101150929999

    • 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。(前后多次读取,数据总量不一致)
    展开全文
  • 今天小编就为大家分享一篇关于Spring中的事务隔离级别的介绍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • mysql的四个事务隔离级别 之前在网上查询mysql事务隔离相关资料,一直只是脑子里有一个印象,久而久之还是会忘记,忘记后又要到网上查找相关资料,但是没实践过就对mysql事务隔离级别理解不是特别的深入,现在自己...
  • mysql事务隔离级别

    2021-08-13 00:28:31
    mysql事务隔离级别:定义了事务事务之间的隔离程度; mysql有四种事务隔离级别: 3. 由隔离性引发的问题 脏读、不可重复度、幻读 4. 演示四种隔离级别 注意:我的mysql是5.7.19,不同版本的命令会有些...
  • java事务隔离级别

    2021-02-12 17:32:01
    事务隔离级别是由数据库系统实现的。Java事务1) 说到事务,不得不提的就是ACID特性,再次回顾:Ø 原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。Ø 一致性(consistency):在...
  • MySQL事务隔离级别详解

    千次阅读 2022-04-28 20:46:43
    一、什么是事务事务是逻辑上的一组操作,要么全执行,要么全不执行。 事务最经典栗子也经常被拿出来的栗子就是银行转账了。比如小明要给小红转账1000元,这个转账会涉及到两个关键操作:将小明的余额减1000元,将...
  • 一、MySQL事务隔离级别读未提交:该级别事务可以读取到其他未提交的事务,造成脏读。读已提交:能读取到其他提交的事务,可以避免脏读,但可造成不可重复读与幻读。可重复读:MySQL默认事务隔离级别,可以解决不可...
  • MySQL Innodb 事务隔离级别

    千次阅读 2021-01-19 11:15:01
    在Mysql中,事务主要有四种隔离级别,今天我们主要是通过示例来比较下,四种隔离级别实际在应用中,会出现什么样的对应现象。Read uncommitted (未提交读)Read committed (已提交读)Repeatable read (可重复读)...
  • 1.查看当前会话隔离级别select @@tx_isolation;2.查看系统当前隔离级别select @@global.tx_isolation;3.设置当前会话隔离级别set session transaction isolatin level repeatable read;4.设置系统当前隔离级别set ...
  • 众所周知,事务隔离级别有四个等级,分别是读未提交(RU),读已提交(RC),可重复读(RR)与串行化(Serial),通过设置隔离级别,可以解决事务并发过程中导致的脏读,不可重复读与幻读。那么隔离级别解决这些问题...
  • SQL 标准定义了四个隔离级别: read-uncommitted(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 read-committed(读取已提交): 允许读取并发事务已经提交的数据...
  • 事务隔离级别:一个事务对数据库的修改与并行的另一个事务的隔离程度。两个并发事务同时访问数据库表相同的行时,可能存在以下三个问题:1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入...
  • Spring事务隔离级别与设置

    千次阅读 2021-06-18 00:42:17
    Spring事务隔离级别比数据库事务隔离级别多一个default 1) DEFAULT (默认) 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。2) READ_...
  • oracle事务隔离级别是学习oracle数据库过程中不能不提到的,下面就为您详细介绍oracle事务隔离级别方面的知识,供您参考。隔离级别(isolation level)oracle事务隔离级别定义了事务与事务之间的隔离程度。oracle事务...
  •  我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式。同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力。所以...
  • 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。数据库事务的隔离级别有4个,下面话不多说了,来一起看看详细的介绍吧。 数据库事务有四种隔离级别: 未提交读(Read Uncommitted):允许脏...
  • SQLServer事务隔离级别

    千次阅读 2020-09-12 11:26:16
    数据库中的事物是具有原子性(Atomicity),一致性(Consistemcy),隔离性(Isolation),持久性(Durability)四个特征。 1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行...
  • 项目中,以 Spring 事务为准,因为他重写了数据库的隔离级别,但没有直接修改数据库的隔离级别

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 175,970
精华内容 70,388
关键字:

事物的隔离级别