精华内容
下载资源
问答
  • 2020-12-29 01:41:04

    1, 脏读

    一个事务读到另一个事务,尚未提交的修改,就是脏读。这里所谓的修改,除了Update操作,不要忘了,还包括

    Insert和Delete操作。

    脏读的后果:如果后一个事务回滚,那么它所做的修改,统统都会被撤销。前一个事务读到的数据,就是垃圾数据。

    举个例子:预订房间。

    有一张Reservation表,往表中插入一条记录,来订购一个房间。

    事务1:在Reservation表中插入一条记录,用于预订99号房间。

    事务2:查询,尚未预定的房间列表,因为99号房间,已经被事务1预订。所以不在列表中。

    事务1:信用卡付款。由于付款失败,导致整个事务回滚。

    所以插入到Reservation 表中的记录并不置为持久(即它将被删除)。

    现在99号房间则为可用。

    所以,事务2所用的是一个无效的房间列表,因为99号房间,已经可用。如果它是最后一个没有被预定的房间,那么这将是一个严重的失误。

    注:脏读的后果很严重。

    2,不可重复读。

    在同一个事务中,再次读取数据时【就是你的select操作】,所读取的数据,和第1次读取的数据,不一样了。就是不可重复读。

    举个例子:

    事务1:查询有双人床房间。99号房间,有双人床。

    事务2:将99号房间,改成单人床房间。

    事务1:再次执行查询,请求所有双人床房间列表,99号房间不再列表中了。也就是说,

    事务1,可以看到其他事务所做的修改。

    在不可重复读,里面,可以看到其他事务所做的修改,而导致2次的查询结果不再一样了。

    这里的修改,是提交过的。也可以是没有提交的,这种情况同时也是脏读。

    如果,数据库系统的隔离级别。允许,不可重复读。那么你启动一个事务,并做一个select查询操作。

    查询到的数据,就有可能,和你第2次,3次...n次,查询到的数据不一样。一般情况下,你只会做一次,select

    查询,并以这一次的查询数据,作为后续计算的基础。因为允许出现,不可重复读。那么任何

    时候,查询到的数据,都有可能被其他事务更新,查询的结果将是不确定的。

    注:如果允许,不可重复读,你的查询结果,将是不确定的。一个不确定的结果,你能容忍吗?

    3,幻读

    事务1读取指定的where子句所返回的一些行。然后,事务2插入一个新行,这个新行也满足事务1使用的查询

    where子句。然后事务1再次使用相同的查询读取行,但是现在它看到了事务2刚插入的行。这个行被称为幻象,

    因为对事务1来说,这一行的出现是不可思议的。

    举个例子:

    事务1:请求没有预定的,双人床房间列表。

    事务2:向Reservation表中插入一个新纪录,以预订99号房间,并提交。

    事务1:再次请求有双人床的未预定的房间列表,99号房间,不再位于列表中。

    注:幻读,针对的是,Insert操作。如果事务2,插入的记录,没有提交。那么同时也是脏读。

    posted on 2009-04-13 12:37 liulang 阅读(7114) 评论(0)  编辑  收藏

    更多相关内容
  • MYSQL避免幻读的方式:(摘自【MYSQL如何解决幻读】) (1) 隔离级别可重复读下,快照读 MVCC + 当前读 Next-Lock Key(只在可重复读隔离级别下生效) (2)隔离级别:SERIALIZABLE,在这个隔离级别下,事务在读操作...

    0. 设置MYSQL的隔离界别

    # 查询数据库当前事务隔离级别
    mysql> select @@global.transaction_isolation,@@transaction_isolation;
    +--------------------------------+-------------------------+
    | @@global.transaction_isolation | @@transaction_isolation |
    +--------------------------------+-------------------------+
    | REPEATABLE-READ                | REPEATABLE-READ         |
    +--------------------------------+-------------------------+
    1 row in set (0.00 sec)
    
    # 设置数据库事务隔离级别为 读未提交
    set global transaction isolation level READ UNCOMMITTED;
    
    # 这一句话只针对当前客户端生效,因此两个客户端都需要
    set session transaction isolation level READ UNCOMMITTED;
    
    # 关闭事务的自动提交
    set autocommit = 0;
    

    1. 脏读

    • 脏读概念:读取了其他事务未提交的数据,可能会造成严重的数据错误(理论上来说如果两个事务都正常提交就没问题)
    事务A事务B
    开启事务开启事务
    查询TOM用户的余额 = 100查询JOHN余额 = 1100
    JOHN给TOM转500
    查询TOM用户的余额 = 600
    TOM用户花300买了个耳机
    JOHN使用的支付转账设备异常,对支付状态校验失败,于是事务回滚
    • 结果:数据异常,余额只有100 的TOM买了个300的耳机。
    • 脏读其实在MYSQL中一般是不会出现的,即使我们手动将MYSQL的隔离级别调整至最低的读未提交,MyISAM的表不支持事务,InnoDB在事务对某行进行修改的时候会自动加上行锁,相当于TOM买耳机的这个操作会被阻塞等待,因此不用对脏读太过担心。

    2. 不可重复读

    • 概念:由于第一次读取和第二次读取同一行记录的时间段中有另一个事务 修改 了数据,导致前后两次读取的结果不一致
    事务A事务B
    开启事务
    查询TOM的余额 = 300
    TOM买了300的耳机
    开启事务
    领导给TOM发了500工资
    提交事务
    再次查询TOM的余额 = 500,欸我怎么原300买300还剩500
    • 结果:在事务A看来,事务期间对于TOM这一行的数据重复读取的时候获得了不一样的结果,数据异常。
    • 不可重复读可以通过设置数据库的隔离级别来进行规避,当数据库的事务隔离级别为Repeatable ReadSerializable 的时候,不可重复读情况消失,具体情况如下图所示:
      在这里插入图片描述

    3. 幻读

    • 概念:事务执行中,有其他事务增删了某些字段,导致本事务没有得到消息,就感觉像出现幻觉一样。
    事务A事务B
    开启事务
    查询用户JACK的余额 = 500
    开启事务
    删除用户JACK
    提交事务
    给JACK用户存200
    查询JACK用户余额,欸怎么查不到JACK用户了??
    • 结果:在事务A进行的过程中,B事务对同一张表的其他数据进行了修改没通知A,导致A做了一些无用的幻觉操作。

    • MYSQL避免幻读的方式:(摘自【MYSQL如何解决幻读】
      (1) 隔离级别可重复读下,快照读 MVCC + 当前读 Next-Lock Key(只在可重复读隔离级别下生效)
      在这里插入图片描述

    (2)隔离级别:SERIALIZABLE,在这个隔离级别下,事务在读操作时,先加表级别的共享锁,直到事务结束才释放;事务在写操作时,先加表级别的排它锁,直到事务结束才释放。也就是说,串行化锁定了整张表,幻读不存在的

    展开全文
  • 数据库的脏读、不可重复读、幻读都和事务的隔离性有关。所以先了解一下事务的4大特性。  事务的4大特性(ACID):  1、原子性(Atomicity):事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么...
  • 隔离级别 描述 READ UNCOMMITED 读未提交数据 允许事务读取未被其他事务提交的变更,脏读,不可重复读和幻读问题都会出现 READ COMMITED读已提交数据 只允许事务读取已被其他事务提交的变更,可以避免脏读,...

    事务的ACID属性

    原子性(Atomictiy)原子性是指事务是一个不可分割的单位,事务中的操作要么都发生,要么都不发生。

    简单的来说就是在事务操作中,比如我通过两条SQL 改两条数据,要么这两个操作都完成,要么都不完成就回滚。

    一致性(Consistency)事务必须从一个一致性状态变换到另一个一致性状态。

    比如转账操作,从A转给B 100元钱,那么A 少100,B 收到100,即这个转账操作就是从未转账状态到转账成功状态,类似于事务一致性的体现。

    隔离性(Isolation)事务的隔离性,是指一个事务的执行不被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    类似于多线程中的线程资源竞争问题。

    持久性(Durability)一个事务一旦被提交,他对数据库中数据的改变是永久性的,接下来的其他操作对数据库故障不应该对其有任何影响。

    事务操作完数据,这个数据就被持久化了,无论数据库断电、还是故障、等都不应该再改变操作完的数据,体现其持久性。

    事务并发引起的问题

    事务并发一般会引起如下三个问题,分别是 脏读、不可重复读、幻读,这三个里面,脏读是我们必须要解决的。

    1.脏读

    对于两个事务,T1 和 T2, T1 读取了已被T2 更新,但是还没有被提交的字段,之后,若T2 回滚,T1 读取的数据就是临时的且无效的数据。

    比方说,改一条数据,事务T1 用于操作改数据,T2 用于读取该后的数据,当T1 在改完还未提交事务时,T2 这个时候去读取T1 的数据,居然读出来时改之后的,这显然是有问题的,因为T1 有可能操作失败回滚,或者说T1 还未改完数据,这时T2 去读未改完的数据显然是不合理的。

    2.不可重复读

    对于两个事务,T1,T2, T1 读取了一个字段,然后T2 更新了该字段,之后T1 再去读取同一个字段,值就不一样了。

    例如,我在买东西的时候,看到库存不足了,这个时候我没有关浏览器,再次刷新了浏览器,结构看到有库存了,这时因为后台数据库增加了库存,而我又没有断开此次事务连接,这样就读取到了最新的数据。(这种情况就是不可重复读问题)

    可重复读,意思是说我一个数据库事务连接 没有断开,读取的就是我这个事务之前读取的数据,数据更新数据(事务提交),我也不应该读取事务提交后的数据,因为我这都是在一个事务中的。就说不管更新数据的事务有没有提交,只要我当前查询的事务没有关闭,就会读取之前我查询出来的状态,不管另一个更新的事务操作。

    我们为了解决不可重复读问题,需要让他可重复读,然而实际上大多数情况 不可重复读问题是 不需要解决的。

    什么又叫可重复读呢?

    意思就算另一个事务,改了数据(即使他commit了),如果 当前 读取数据的事务操作没有关闭,则读取的数据就还是之前的数据,如图:

    这种模式下,想要读取提交后的数据,必须重新起一个事务。

    3.幻读

    对于两个事务 T1,T2 T1从一张表中读取了一个字段后,然后T2在表中 插入了一些新的行,之后,如果T1 再次读取同一个表,就会多出几行。

    这里它强调的是插入操作,例如我一个事务T1读数据读出了100条,另一事务T2此时正在向此表插入数据,这时我第一个事务T1读出来就比100条多了,这种情况就是幻读。

    总结

    注意: 不可重复读,指的是 更新 操作,而幻读,指的是 插入 操作。

    一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务的隔离级别,不同隔离级别应对不同的干扰程度。

    隔离级别越高,数据一致性就越好,但并发性就越弱,类似于多线程加锁,隔离性好但性能差。

    一般情况下,不可重复读问题是可以接受的,一般我们只需要解决脏读的问题。

    四种隔离级别

    隔离级别

    描述

    READ UNCOMMITED 读未提交数据

    允许事务读取未被其他事务提交的变更,脏读,不可重复读和幻读问题都会出现

    READ COMMITED读已提交数据

    只允许事务读取已被其他事务提交的变更,可以避免脏读,但不可重复读和幻读问题依然存在

    REPEATABLE READ 可重复读

    确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读问题,但幻读问题依然存在。

    SERIALLZABLE 串行化

    确保事务可以从一个表中读取相同约行,在这个事务持续期间,禁止其他事务对表执行插入更新删除操作,所有问题都可避免,但性能十分低下

    Oracle 支持2种事务隔离级别,READ COMMITED, SERIALIZABLE. 它默认隔离级别为 READ COMMITED.

    隔离级别越往下,则 一致性越好,并发性越差。

    一般情况下,脏读问题必须解决,不可重复读和幻读问题是可以接受的。

    Java 隔离级别演示

    如下代码

    一段查询代码,根据设置的隔离级别查询数据,隔离级别如下:

    TRANSACTION_REPEATABLE_READ 为可重复读,避免了脏读和可不可重复读问题.

    TRANSACTION_READ_UNCOMMITTED 读未提交数据,这种隔离级别存在脏读,会读取未提交的数据

    TRANSACTION_READ_COMMITTED 读已提交的数据,如果修改的数据未提交,则读出来还是老的修改之前的数据

    TRANSACTION_SERIALIZABLE 串行化,解决了脏读,不可重复读,幻读。 一般不用,因为并发效率低。

    查询更新的数据

    一般我们都会将隔离级别设置为 TRANSACTION_READ_COMMITTED, 这样更新的事务如果没有提交,则读取的都是之前的值,这里只会读取已提交的数据。

    @Test

    public void testTransactionSelect() {

    Connection conn = JDBCUtils.GetDBConnection();

    try {

    //获取取数据库的隔离级别,当前为TRANSACTION_REPEATABLE_READ

    //TRANSACTION_REPEATABLE_READ 为可重复读,避免了脏读和可不可重复读问题.

    //TRANSACTION_READ_UNCOMMITTED 读未提交数据,这种隔离级别存在脏读,会读取未提交的数据

    //TRANSACTION_READ_COMMITTED 读已提交的数据,如果修改的数据未提交,则读出来还是老的修改之前的数据

    conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

    System.out.println(conn.getTransactionIsolation());

    //取消自动提交数据

    conn.setAutoCommit(false);

    String sql = "SELECT `user`,`password`,balance FROM balance WHERE `user` = ?";

    DBCommand dbCommand = new DBCommand(conn);

    BalanceEntity balance1 = dbCommand.queryMethod(BalanceEntity.class, sql, "jerry");

    System.out.println(balance1);

    } catch (Exception ex) {

    ex.printStackTrace();

    }finally {

    try {

    conn.close();

    } catch (SQLException throwables) {

    throwables.printStackTrace();

    }

    }

    }

    更新数据操作

    如下更新操作中,将数据库中的balance改为6000,中途等待15秒后提交,那么在这15秒内,查询数据库中的数据依然是之前的值。

    @Test

    public void testTransactionUpdate() {

    Connection conn = JDBCUtils.GetDBConnection();

    DBCommand dbCommand = new DBCommand(conn);

    try {

    String sql = "UPDATE balance SET `balance` = ? WHERE `user`= ?";

    conn.setAutoCommit(false);

    int updateResult = dbCommand.updateMethod(conn, sql, 6000, "jerry");

    if (updateResult > 0) {

    System.out.println("更新数据成功!");

    }

    Thread.sleep(15000);

    conn.commit();

    } catch (Exception ex) {

    ex.printStackTrace();

    }finally {

    try {

    conn.close();

    } catch (SQLException throwables) {

    throwables.printStackTrace();

    }

    }

    }

    如之前的值为 2000 ,隔离级别设置为 TRANSACTION_READ_COMMITTED,那么在这15秒未提交的时间里,数据库查询结果和代码结果都是2000:

    数据库中查询结果

    代码中查询结果

    15秒后,数据提交,则查询结果如下:

    展开全文
  • MySQL如何避免幻读

    千次阅读 2021-11-14 15:00:03
    事务的并发问题 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据 不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对...MySQL如何实现避免幻读 在快照读读情况下

    事务的并发问题

    1. 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
    2. 不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
    3. 幻读:A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。select某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

    MySQL如何实现避免幻读

    • 在快照读读情况下,MySQL通过MVCC来避免幻读。
    • 在当前读读情况下,MySQL通过next-key来避免幻读

    什么是MVCC

    MVCC全称是多版本并发控制的简称(multi version concurrent control)。MySQL把每个操作都定义成一个事务,每开启一个事务,系统的事务版本号自动递增。每行记录都有两个隐藏列:创建版本号和删除版本号

    MVCC多版本并发控制是MySQL中基于乐观锁理论实现隔离级别的方式,用于读已提交和可重复读取隔离级别的实现。

    在MySQL中,会在表中每一条数据后面添加两个字段:最近修改该行数据的事务ID,指向该行(undolog表中)回滚段的指针。

    Read View判断行的可见性,创建一个新事务时,copy一份当前系统中的活跃事务列表。意思是,当前不应该被本事务看到的其他事务id列表。已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。

    • select:事务每次只能读到创建版本号小于等于此次系统版本号的记录,同时行的删除版本号不存在或者大于当前事务的版本号。

    • update:插入一条新记录,并把当前系统版本号作为行记录的版本号,同时保存当前系统版本号到原有的行作为删除版本号。

    • delete:把当前系统版本号作为行记录的删除版本号

    • insert:把当前系统版本号作为行记录的版本号

    什么是next-key锁

    InnoDB 采用 Next-Key Lock 解决幻读问题。

    insert into test(xid) values (1), (3), (5), (8), (11)
    

    在这条语句执行后,由于xid上是有索引的,该算法总是会去锁住索引记录
    现在,该索引可能被锁住的范围如下:(-∞, 1], (1, 3], (3, 5], (5, 8], (8, 11], (11, +∞)。

    select * from test where id = 8 for update
    

    这条语句执行后会锁住的范围:(5, 8], (8, 11]。
    除了锁住8所在的范围,还会锁住下一个范围,所谓Next-Key。

    展开全文
  • 如何防止数据脏读幻读

    千次阅读 2018-01-13 22:27:00
    脏读、不可重读度、幻读,其实都是数据库的一致性问题,必须由一定的事务隔离机制来解决。 其中一种方法是:不用加锁,通过一定的机制生成一个数据请求时间点的一致性快照,并用这个快照来提供一个界别的一致性...
  • 数据库的脏读幻读,幻行的原理及解决方式

    千次阅读 多人点赞 2019-03-26 10:50:38
    数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。 √: 可能出现×: 不会出现 脏读...
  • 本篇文章小编将为大家介绍,.NET中 关于脏读 不可重复读与幻读的代码示例,有需要的朋友可以参考一下
  • 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。 √: 可能出现×: 不会出现 脏读...
  • 既然支持事务,那么就会有处理并发事务带来的问题:更新丢失、脏读、不可重复读、幻读;相应的为了解决这四个问题, 就产生了事务隔离级别:未提交读(Read uncommitted),已提交读(Read committed),可重复读...
  • 数据库的两种读,每种读读的数据版本不一样,所以也称为MVCC,即多版本并发控制a) 快照读select * from where xxx 这种形式的都是快照读。b) 当前读update , insert ,delete ,... 不可重复读与幻读的区别:从总的结...
  • 序言脏读、不可重复读、幻读这几个概念开始接触和学习的时候是在大学学习数据库系统的时候,那时候对这几个专业名词的理解停留在概念文字上,并没有真正使用过实践中,最近工作中涉及到这几个概念方面的知识,就来...
  • 避免脏读、不可重复读和幻读的发生。 4. Serializable(序列化) 最高隔离级别。所有事务操作依次顺序执行。会导致大量的超时以及锁竞争,同时导致并发度下降,性能最差。不建议生产使用。 四、不同事务级别带来的...
  • 解决第一类丢失更新的问题,但是会出现脏读、不可重复读、第二类丢失更新的问题,幻读 。 可以读取未提交记录。此隔离级别,不会使用,忽略。 1.2 Read Committed (RC) 快照读忽略,本文不考虑。  保证一个...
  • 脏读幻读和不可重复读

    千次阅读 2022-06-06 15:25:59
    一、脏读、不可重复读、幻读1、脏读脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 例如: 张三的工资为...
  • 本章着重点是介绍:出现脏读幻读、不可重复读的原因,以及设定四种隔离级别如何解决这些现象,结合图例让读者阅读得更加通透 一、什么是事务? 所谓事务是用户定义的一个数据库序列,这些操作要么全做,要么全不...
  • 【数据库】快速理解脏读、不可重复读、幻读

    万次阅读 多人点赞 2018-08-14 19:24:29
    快速理解脏读、不可重复读、幻读? 理解这三种由于并发访问导致的数据读取问题,再理解事务隔离级别就简单多了。 【1】脏读(读取未提交数据) A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行...
  • 并发场景下mysql会出现脏读幻读、不可重复读问题; 脏读(dirty read): 某个事务正在修改数据但未提交,此时另一个事务去读取此条数据,后一个事务读取的不是最新的数据,是错误的。 解决办法:读取时加排它锁...
  • 1、数据脏读 事务a修改了某条数据,然后事务b读取了事务a修改的该条数据,然后事务a由于某些原因,事务a回滚了,这样事务b读到的数据就和回滚的数据不同了,这时事务b读取的数据就是脏数据。概况一句话就是一个事务...
  • Mysql有四种事务隔离级别,这四种隔离级别代表当存在多个事务并发冲突时,可能出现的脏读、不可重复读、幻读的问题。 脏读 大家看一下,我们有两个事务,一个是 Transaction A,一个是 Transaction B,在第一个事务...
  • 事务的特性:原子性:指处于同一个事务中的多条语句是不可分割的。一致性:事务必须使数据库从一个一致...事务隔离性问题:如果不考虑事务的隔离性,会出现以下问题:脏读:指一个线程中的事务读取到了另外一个线程...
  • 脏读 一个事务访问到了其他事务未提交的数据更改 例:事务A对一个数据进行了修改操作,但事务A未提交,事务B在查询时却查到了修改后的数据。 脏数据:事务B查询到事务A修改后的数据,但是事务A回滚了,此时事务B...
  • 数据库事务中谈的最多的就是事务的隔离级别,事务并发还行中最常见的问题又有脏读幻读、不可重复读。这篇文章就主要来介绍一下这些问题。 脏读 脏读是指一个事务读取到其他事务没有提交的数据。 不可重复读 不可...
  • 脏读 脏读是指一个是事务查询到另一事务还未提交的信息 隔离级别 READ_UNCOMMITTED 例如 (1)事务A执行了一次查询 (2)事务B执行了一次更新语句 (3)事务A再次执行一次查询 此时,事务A查询到的是事务B还未提交的...
  • 详解-脏读幻读与不可重复读

    千次阅读 2020-10-17 13:22:46
    最近在读 《MySQL 技术内幕 InnoDB 存储引擎》,里面提到的各种概念都很新鲜,以前听说过脏读幻读、不可重复读,但是对于概念不甚了解,于是查了一下,这里做个笔记。数据库事务特征...
  • 脏读 (针对未提交数据) 脏读又称无效数据读出(读出了脏数据)。一个事务读取另外一个事务还没有提交的数据叫脏读。 例如:事务T1修改了某个表中的一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后...
  • 脏写 有两个事务A、B同时更新一条数据,事务A先更新为A值,事务...但是事务A突然进行回滚了,这行数据又回到了NULL值,接着,事务B读取这数据发现怎么和之前读到的A值不一样了,这就是脏读。 事务B由于事务A的回滚读不
  • 脏读脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。 幻读幻读是指当事务不是独立执行时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,959
精华内容 23,183
关键字:

如何避免脏读幻读

友情链接: trig_draft_init.rar