精华内容
下载资源
问答
  • 主要介绍了MySQL事务及Spring隔离级别实现原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 前言 ...我们都知道事务的几种性质,数据库中的一致性和隔离性等是实现事务的基本思想,在系统有大量的并发访问的情况下,了解和熟练应用数据库的本身的事务隔离级别,对于写出健壮性,并发处理能力强
  • 事务隔离级别实现

    2017-04-22 11:36:20
    事务隔离级别就是通过各种锁来实现的。一般设置在应用程序上。 1.read uncommitted 可读未提交的,允许脏读。  即:不加锁,事务TA可能读到TB中还未提交的数据。如果TB回滚,就读到了被回滚的数据。 2.read ...
    事务的隔离级别就是通过各种锁来实现的。一般设置在应用程序上。

    展开全文
  • 为了保证事务操作的原子性,必须实现基于日志的REDO/UNDO机制:将所有对数据的更新操作都写入日志,如果一个事务中的一部分操作已经成功,但以后的操作,由于断电/系统崩溃/其它的软硬件错误而无法继续,则通过回溯...

    一、ACID特性

    持久性,我们就不讲了,易懂。

    1、原子性

    在同一个事务内部的一组操作必须全部执行成功(或者全部失败)。

    为了保证事务操作的原子性,必须实现基于日志的REDO/UNDO机制:将所有对数据的更新操作都写入日志,如果一个事务中的一部分操作已经成功,但以后的操作,由于断电/系统崩溃/其它的软硬件错误而无法继续,则通过回溯日志,将已经执行成功的操作撤销,从而达到“全部操作失败”的目的。 最常见的场景是,数据库系统崩溃后重启,此时数据库处于不一致的状态,必须先执行一个crash recovery的过程:读取日志进行REDO(重演将所有已经执行成功但尚未写入到磁盘的操作,保证持久性),再对所有到崩溃时尚未成功提交的事务进行UNDO(撤销所有执行了一部分但尚未提交的操作,保证原子性)。crash recovery结束后,数据库恢复到一致性状态,可以继续被使用。

    某个应用在执行转帐的数据库操作时,必须在同一个事务内部调用对帐户A和帐户B的操作,才能保证数据的一致性。

    但是,原子性并不能完全保证一致性。在多个事务并行进行的情况下,即使保证了每一个事务的原子性,仍然可能导致数据不一致的结果。 例如,事务1需要将100元转入帐号A:先读取帐号A的值,然后在这个值上加上100。但是,在这两个操作之间,另一个事务2修改了帐号A的值,为它增加了100元。那么最后的结果应该是A增加了200元。但事实上,事务1最终完成后,帐号A只增加了100元,因为事务2的修改结果被事务1覆盖掉了。

    简而言之,就是:原子性仅能够保证单个事务的一致性。就像redis一样,也只能保证单操作的线程安全,并不能保证多操作下的线程安全。

    2、一致性

    按照我个人的理解,在事务处理的ACID属性中,一致性是最基本的属性,其它的三个属性都为了保证一致性而存在的。

    我们举个反例来理解下一致性概念。例如:从帐户A转一笔钱到帐户B上,如果帐户A上的钱减少了,而帐户B上的钱却没有增加,那么我们认为此时数据处于不一致的状态。

    为了保证并发情况下的一致性,引入了隔离性,即保证每一个事务能够看到的数据总是一致的,就好象其它并发事务并不存在一样。

    3、隔离性

    数据库四种隔离级别,以及常见的几种读异常,大家应该都是耳熟能详的,但数据库底层是怎么实现隔离性的呢?都采用了哪些技术呢? 主要有两个技术:MVCC(多版本并发控制)和锁。

    (1)MVCC(多版本并发控制)

    多版本并发控制,顾名思义,在并发访问的时候,数据存在版本的概念,可以有效地提升数据库并发能力,常见的数据库如MySQL、MS SQL Server、IBM DB2、Hbase、MongoDB等等都在使用。

    简单讲,如果没有MVCC,当想要读取的数据被其他事务用排它锁锁住时,只能互斥等待;而这时MVCC可以通过提供历史版本从而实现读取被锁的数据的历史版本,从而避免了互斥等待。

    InnoDB采用的MVCC实现方式是:在需要时,通过undo日志构造出历史版本。

    (2)锁

    1) 锁的分类

    • Shared Locks(共享锁/S锁)

    若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

    • Exclusive Locks(排它锁/X锁)

    若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。在更新操作(INSERT、UPDATE 或 DELETE)过程中始终应用排它锁。

    注意:排他锁会阻止其它事务再对其锁定的数据加读或写的锁,但是不加锁的就没办法控制了。

    • Record Locks(行锁)

    行锁,顾名思义,是加在索引行(对!是索引行!不是数据行!)上的锁。比如select * from user where id=1 and id=10 for update,就会在id=1id=10的索引行上加Record Lock。

    • Gap Locks(间隙锁)

    间隙锁,它会锁住两个索引之间的区域。比如select * from user where id>1 and id<10 for update,就会在id为(1,10)的索引区间上加Gap Lock。

    • Next-Key Locks(间隙锁)

    也叫间隙锁,它是Record Lock + Gap Lock形成的一个闭区间锁。比如select * from user where id>=1 and id<=10 for update,就会在id为[1,10]的索引闭区间上加Next-Key Lock。

    这样组合起来就有,行级共享锁,表级共享锁,行级排它锁,表级排它锁。

    2) 什么时候会加锁?

    在数据库增删改查四种操作中,insert、delete和update都是会加排它锁(Exclusive Locks)的,而select只有显式声明才会加锁:

    • select: 即最常用的查询,是不加任何锁的
    • select ... lock in share mode: 会加共享锁(Shared Locks)
    • select ... for update: 会加排它锁

    3) 四种隔离级别

    不同的隔离级别是在数据可靠性和并发性之间的均衡取舍,隔离级别越高,对应的并发性能越差,数据越安全可靠。

    • READ UNCOMMITTED

    顾名思义,事务之间可以读取彼此未提交的数据。机智如你会记得,在前文有说到所有写操作都会加排它锁,那还怎么读未提交呢?

    机智如你,前面我们介绍排它锁的时候,有这种说明: 排他锁会阻止其它事务再对其锁定的数据加读或写的锁,但是对不加锁的读就不起作用了。

    READ UNCOMMITTED隔离级别下, 读不会加任何锁。而写会加排他锁,并到事务结束之后释放。

    实例1:

    查-写:查并没有阻止写,表明查肯定并没有加锁,要不写肯定就阻塞了。写很明显,会加排它锁的。

    实例2: 写-写:阻塞,表明,写会加排它锁。

    • READ COMMITTED

    顾名思义,事务之间可以读取彼此已提交的数据。

    InnoDB在该隔离级别(READ COMMITTED)写数据时,使用排它锁, 读取数据不加锁而是使用了MVCC机制。

    因此,在读已提交的级别下,都会通过MVCC获取当前数据的最新快照,不加任何锁,也无视任何锁(因为历史数据是构造出来的,身上不可能有锁)。

    但是,该级别下还是遗留了不可重复读和幻读问题: MVCC版本的生成时机: 是每次select时。这就意味着,如果我们在事务A中执行多次的select,在每次select之间有其他事务更新了我们读取的数据并提交了,那就出现了不可重复读,即:重复读时,会出现数据不一致问题,后面我们会讲解超支现象,就是这种引起的。

    • REPEATABLE READ

    READ COMMITTED级别不同的是MVCC版本的生成时机,即:一次事务中只在第一次select时生成版本,后续的查询都是在这个版本上进行,从而实现了可重复读

    但是因为MVCC的快照只对读操作有效,对写操作无效,举例说明会更清晰一点: 事务A依次执行如下3条sql,事务B在语句1和2之间,插入10条age=20的记录,事务A就幻读了。

    1. select count(1) from user where age=20;
    -- return 0: 当前没有age=20的
    2. update user set name=test where age=20;
    -- Affects 10 rows: 因为事务B刚写入10条age=20的记录,而写操作是不受MVCC影响,能看到最新数据的,所以更新成功,而一旦操作成功,这些被操作的数据就会对当前事务可见
    3. select count(1) from user where age=20;
    -- return 10: 出现幻读
    

    REPEATABLE READ级别,可以防止大部分的幻读,但像前边举例读-写-读的情况,使用不加锁的select依然会幻读。

    • SERIALISABLE

    大杀器,该级别下,会自动将所有普通select转化为select ... lock in share mode执行,即针对同一数据的所有读写都变成互斥的了,可靠性大大提高,并发性大大降低。

    读-写,写-写均互斥。

    4)总结:几类读异常

    读-写-读,引起的异常

    • 脏读:读取了脏数据(不存在的数据)。 事务一读 事务二写(未提交) 事务二读(脏数据) 事务二回滚

    • 不可重复读:既可以读取修改的数据,也可以读取新增的数据(幻读)。 事务一读 事务二写(更新已提交) 事务二读(数据不一致,不可重复读)

    • 幻读:仅可以读取新增的数据,但是无法读取修改的数据; 事务一读 事务二写(新增已提交) 事务二读(数据不一致,幻读)

    • 附命令

    查看表的加锁情况: select * from information_schema.INNODB_LOCKS; 事务状态 select * from information_schema.INNODB_TRX;

    展开全文
  • MySQL的事务隔离级别是怎么实现的?

    千次阅读 2019-03-12 23:09:29
    MySQL的隔离级别以及各个隔离级别实现的原理

    一、MySQL有哪几种事务隔离级别?

          1.读未提交

    读的都是最新版本的数据,会出现脏读

           2.读已提交

    读的都是已提交的数据,会出现不可重复读

           3.可重复读

    解决了不可重读的问题,InnoDB解决了幻读问题

           4.串行化

    用加锁的方式实现串行化

    二、事务的隔离级别是怎么实现的?

    每行数据其实在数据库都是多个版本的,可能同一时间有很多事务在更新一条数据,事务在开始的时候会申请一个id,这个id是严格随着时间递增的,先开始的事务id总是小的,数据库的版本就是事务id的版本。

          1.读未提交

    每次读的都是最新版本,这样速度是最快的,使用中的业务场景基本上没有

         2.读已提交

     如果当前数据版本的号(最新事务对这条数据的操作)比事务的id大,就会根据版本的id查看事务是否提交了,如果提交了,就会承认这条数据,如果查到这个事务还没有提交,就会查看上个版本,直到找到已提交的版本,获取那个版本的数据,那有没有读到的版本是已提交的,上个版本还没提交呢,当然是不会的,更新的时候会加上一个行锁,上个事务如果没有提交,这个事务是不可能提交的

      3.可重复读

    可重读读在事务启动的时候获取一个数组,记录未提交的事务,可重复读取数据的时候多了一个验证,如果事务提交了但是数据的版本号(操作这个数据事务的id)比当前事务高,说明这个事务是在当前事务启动后启动并且提交的,这条数据是不会被承认的,如果当数据的版本号比当前事务id低的话,说明操作是在当前事务开启之前就开启了,这条数据是被当前事务承认的。

    可以发现InoDB引擎是通过MVCC解决了幻读的问题。

    4.串行化

    用加锁的方式来避免并行访问

    5.视图

    读已提交和可重复读都有视图概念的,读已提交获取的是最新提交的视图,可重复读在事务启动的时候就开启,保证事务内读到的数据是一样的,比如一个事务 执行了两次 select city from tb_user where id = 100 ,中间有一个新的事务执行了修改操作,对于可重复读,两次查询结果都是一样的,对于读已提交,两次结果就不一样了。

     

     

    展开全文
  • 项目中,以 Spring 事务为准,因为他重写了数据库的隔离级别,但没有直接修改数据库的隔离级别

    原创博文,欢迎转载,转载时请务必附上博文链接,感谢您的尊重。

    前言

    通过本篇,你将了解到【Spring事务】与【数据库事务】的关系,以及优先级问题,我将为你一一论证。

    阅读本篇,你可能会需要的博文:


    正文

    数据库是可以控制事务的传播和隔离级别的,Spring在之上又进一步进行了封装,可以在不同的项目、不同的操作中再次对事务的传播行为和隔离级别进行策略控制。

    所以说,spring事务本质上使用数据库事务,而数据库事务本质上使用数据库锁,所以spring事务本质上使用数据库锁,开启spring事务意味着使用数据库锁。

    上面的“总结”来自网络,结合自身理解与实践,的确可以最为一句精华,本文内容主要围绕这句话展开,以2个问题的形式阐明观点。

    1. Spring定义的隔离级别和数据库设置的隔离级别,二者是什么关系?
    2. 如果Spring定义的隔离级别和数据库设置的隔离级别不一样,以谁的为准?

    一、两者的关系

    详情在我的其他博文都有具体介绍(需要的朋友见本文【前言】提示),这里就不赘述了,我们直接对比结果。

    1. 数据库的隔离级别:

    MySQL 默认为 :EPEATABLE_READ;Oracle,sql server 默认为:READ_COMMITTED;READ_UNCOMMITTED 由于隔离级别较低,通常不会被使用。

    √: 可能出现    ×: 不会出现
    隔离级别隔离级别的值脏读不可重复读幻读
    Read uncommitted(未提交读)0
    Read committed(已提交读)1×
    Repeatable read(可重复读)2××
    Serializable(可串行化)3×××

    2. Spring事务的隔离级别:

    Spring事务由 @Transactional 注解实现,隔离级别由它的参数 isolation 控制,Isolation 的 Eum 类中定义了“五个”表示隔离级别的值,如下。

    √: 可能出现    ×: 不会出现
    Isolation的值与隔离级别隔离级别的值脏读不可重复读幻读
    Isolation.DEFAULT0---
    Isolation.READ_UNCOMMITTED1
    Isolation.READ_COMMITTED2×
    Isolation.REPEATABLE_READ4××
    Isolation.SERIALIZABLE8×××

    Isolation.DEFAULT 是 PlatfromTransactionManager 默认的隔离级别,它的含义是:使用数据库默认的事务隔离级别

    除此之外,另外四个与 JDBC 的隔离级别是相对应的,就好像 Java 里的重写一样,所以说:Spring事务隔离级别是在数据库隔离级别之上又进一步进行了封装。

    二、 不一致会怎样

    既然是封装,那么Spring项目应该就是以Spring事务为准的,除非使用 @Transactional(isolation = Isolation.DEFAULT)时,才会使用数据库设置的隔离级别。

    为了验证这个猜想,我们还是找到源码解读一下,从JDBC开始说起吧。

    1. JDBC 加载流程

    每一个 Spring 事务管理,都涉及到了与数据库的交互,也必然涉及到了JDBC连接。

    JDBC 加载的流程还记得吧,肯定都被问过,有四步:注册驱动,建立连接,发起请求,输出结果。写一段伪代码:

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try{
            // 1.注册 JDBC 驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.创建链接
            System.out.println("连接数据库...");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_db","root","root");
            // 3.发起请求
            stmt = conn.createStatement();
            String sql = "SELECT id, name, url FROM websites";
            rs = stmt.executeQuery(sql);
            // 4.输出结果
            System.out.print("查询结果:" + rs);
            // 关闭资源(演示代码,不要纠结没有写在finally中)
            rs.close();
            stmt.close();
            conn.close();
        } catch (SQLException se)
            se.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }

    在创建连接阶段,JDBC 从数据库获取一个连接 Connection 对象,该对象不仅有连接数据库的方法,还有设置当前连接的事物隔离级别的方法。

    2. Connection  源码解释

    Connection 实体类中包含了 void setTransactionIsolation(int level) throws SQLException;设置设置当前连接的事物隔离级别的方法。

    Spring 约定了使用 @Transactional 注解的形式实现事务特性,而隔离级别的开启,也是注解的形式实现,如:开启事务的串行级别 —— @Transactional(isolation = Isolation.SERIALIZABLE)。

    源码截不全,我复制一下:

    /**
    * 这是 Connection 连接的部分源码
    */
    public interface Connection  extends Wrapper, AutoCloseable {
    
        ... 
    
        /**
        * 尝试将此连接对象的事务隔离级别更改为给定的级别
        * 接口连接中定义的常量是可能的事务隔离级别
        */
        void setTransactionIsolation(int level) throws SQLException;
    
        ...
    }
    

    该方法的注释说明:尝试将此连接对象的事务隔离级别更改为给定的级别,如果在事务期间调用此方法,则结果由实现定义。

    没错,强调的就是本次连接 Connection,所以,如果spring与数据库事务隔离级别不一致时,以spring为准。

    3. 验证

    阐述一下方法:

    • 首先,验证测试数据库的隔离级别 Select @@tx_isolation;
    • 写一个包含update,save的与测试数据库交互的方法;
    • 分别验证加上@Transactional(isolation = Isolation.SERIALIZABLE)注解前后,测试数据库的隔离级别是否变化!!

    以我的测试数据库为例,结果没有发生变化,都是 READ_COMMITTED。

    这只是简单的验证下Spring事务隔离级别的修改,是否会直接影响数据库的隔离级别,结论是没有。

    不太严谨,但是证明了我的猜想,后期我会在Sping项目中,通过测试代码进一步验证“修改隔离级别以成功运用到Spring事务中”。

    三、总结

    • 数据库是可以控制事务的传播和隔离级别的,Spring在之上又进一步进行了封装,可以在不同的项目、不同的操作中再次对事务的传播行为和隔离级别进行策略控制;
    • 项目中,以 Spring 事务为准,因为他重写了数据库的隔离级别,但没有直接修改数据库的隔离级别;
    • 项目中,如果 Spring 事务隔离级别设置为(isolation = Isolation.DEFAULT)默认数据库优先时,以数据库的隔离级别为准。

    小编怀着忐忑的心情,上传了本篇博文,如果有错误,还请大佬指正!!后期也会补全自己的验证手段!!

    That's all,thank you!


    我是IT无知君,您的点赞、评论和关注,是我创作的动力源泉。
    学无止境,气有浩然,让我们一起加油,天涯未远,江湖有缘再见!!

    展开全文
  • 主要是通过视图的方式来实现的:数据库里面会创建一个视图,访问的时候以视图的逻辑为准. 读未提交: 直接返回记录上的最新值,没有视图概念. 读已提交: 在每个SQL语句开始执行的时候创建视图,所以在查询SQL执行前如果...
  • 本篇博客介绍InnoDB的四种事务隔离级别是如何实现的, 需要事先阅读上面的两篇博客. REPEATABLE READ InnoDB并发控制 这篇博客最后一部分对REPEATABLE READ隔离级别是如何实现做了详细介绍, 这里做个简单的归纳. 普通...
  • 之前在《数据库事务与锁详解》中讲解了事务的概念、事务引发的问题以及通过隔离性避免这些问题、锁的概念。 这里就来讲讲InnoDB引擎中隔离性是怎么实现的。 READ COMMITED 和 REPEATABLE READ 的隔离实现:MVCC ...
  • Innodb中的事务隔离级别实现原理

    千次阅读 2018-10-08 17:34:34
    我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式。同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力。所以对于...
  • 由于Mysql 默认的隔离级别是...本文只介绍事务隔离级别相关的特性 违反事务隔离级别的几个特征 首先需要了解一下违反事物隔离级别的几个特征: 脏读 当前事务中读取到了其它没有提交的事务修改的数据———读.
  • 数据库事务隔离级别实现原理

    千次阅读 2019-03-11 10:52:29
    事物的四大特性,即常说的ACID: 1、原子性(Atomic):指的... 3、隔离性(Isolation):指的是多个事物并发执行的时候、一个事物的执行不应当影响到其它的事物、即事物与事物之间是隔离的。 4、持久性(Durabil...
  • 近来需要学习的东西实在太多了,看了容易忘记。准备写个blog记录下,方便以后复习。本文主要是讲解mysql的事务隔离级别和不同级别所出现的问题。
  • 事务隔离级别

    万次阅读 多人点赞 2019-05-20 20:22:47
    事务隔离级别 事务的四大特性分别是:原子性、一致性、隔离性、持久性 幻读和不可重复读都是在同一个事务中多次读取了其他事务已经提交的事务的数据导致每次读取的数据不一致,所不同的是不可重复读读取的是同一条...
  • 1.数据库事务 ...事务由事务开始与事务结束之间执行的全部数据库操作组成。 其实transaction也可以翻译成交易,比如大家耳熟能详的银行转账交易。交易成功的核心就在于A账户的转出操作与B账户的转入操...
  • mysql的事务是innodb存储引擎独有的,myisam存储引擎不支持事务。 事务最经典的例子就是转账了,事务要保证的是一组数据库的操作要么全部成功,要么全部失败。...事务隔离级别 事务的隔离级别有4个层级,隔离级别依
  • MySQL事务隔离级别详解

    万次阅读 多人点赞 2018-12-27 00:45:23
    在MySQL中,事务支持实在引擎层实现的,MySQL是一个支持多引擎的系统,但并不是所有引擎都支持事务。比如MySQL原生的 MyISAM 引擎就不支持事务,这也是 MyISAM 被取代的原因之一。 隔离事务的四大特性AC...
  • 仅从ACID或非ACID角度考虑问题是不够的,你应知道你的数据库支持何种事务隔离...在本文中,我们将解释什么是事务隔离级别和脏读,并给出一些广受欢迎的数据库是如何实现它们的。ANSISQL给出了四种标准的事务隔离级别
  • MySQL事务隔离级别实现原理

    千次阅读 2018-12-27 22:38:51
    在MySQL的众多存储引擎中,只有InnoDB支持事务,所有这里讨论的事务隔离级别指的是MySQL InnoDB下的事务隔离级别,一般而言,隔离级别分为:读未提交:一个事务可以读取到另一个事务未提交的修改。这会带来脏读、幻...
  • Spring事务隔离级别详解

    千次阅读 2019-11-13 09:17:00
    摘要:本文主要讲解Spring中的事务隔离级别。 当两个事务对同一个数据库的记录进行操作时,那么,他们之间的影响是怎么样的呢?这就出现了事务隔离级别的概念。数据库的隔离性与并发控制有很大关系。ACID,即...
  • Spring事务隔离级别

    万次阅读 多人点赞 2019-02-23 23:27:28
      事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题: 问题 描述 脏读 一个事务读到另...
  • 事务隔离级别原理详解

    千次阅读 2018-03-01 17:47:39
    背景 当用户并发尝试访问同一数据的时,SQL Server尝试用锁来隔离不一致的数据和使用隔离级别查询数据时控制一致性(数据该如何读取),说起锁就会联想到事务事务是一个工作单元,包括查询/更新数据和数据定义。...
  • 一直没搞清楚spring事务与数据库事务与锁之间的关系。...本人认为事务隔离级别是通过锁的机制实现的,事务隔离级别是数据库开发商根据业务逻辑的实际需要定义的一组锁的使用策略。当我们将数...
  • oracle 默认的事务隔离级别

    千次阅读 2021-01-27 17:29:57
    2.隔离级别实现上一节介绍了ANSI定义的3种异象,及根据禁止异象的个数而定义的事务隔离级别。因为不存在严格、严谨的“官方”定义,各主流2.1 Lock-based 隔离级别实现在展示Lock-based隔离级别实现前,先介绍几个与...
  • SQLServer事务隔离级别

    千次阅读 2020-09-12 11:26:16
    数据库中的事物是具有原子性(Atomicity),一致性(Consistemcy),隔离性(Isolation),持久性...3、夺隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。 4、夺持久性(Dura
  • PG数据库事务隔离级别

    千次阅读 2017-01-28 14:33:19
    Postgres数据库事务隔离级别介绍

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 110,833
精华内容 44,333
关键字:

事务隔离级别由谁实现