• 再谈数据库隔离级别


    前言

    在“数据库事务和事务的隔离级别”一文中,事务的隔离级别有如下4中隔离级别,

    1.未授权读取,read uncommitted

    2.授权读取,read committed

    3.可重复读取,repeatable read

    4.串行化,serializable

    这次我以mysql为例,通过实际操作演示一下这四种隔离级别。

    笔者使用的mysql版本是5.6.41,我们可以在客户端调用version()用来查看数据可的版本。

    我们通过客户端通过@@tx_isolation查看一下mysql默认设置的事务隔离级别是REPEATABLE-READ

    事务隔离级别设置

    在“数据库事务和事务的隔离级别”,笔者已经提出了当前会话事务隔离级别和全局事务隔离级别。

    更改当前会话事务隔离级别:set session transaction isolation level serializable

    更改全局事务隔离级别:set global transaction isolation level serializable

    语法:set [session | global] transaction isolation level [read uncommitted  | read committed |  repeatable read |  serlializable];

    毫无疑问,当前会话,往往用于开发或者测试人员在工作过程中,用于单元测试,而全局事务的更改往往用于实际的应用环境中。但是大多数据库一般使用了数据库默认的事务隔离级别。我们来演示一下,现在我们把当前会话的事务隔离级别更改为  未授权读取read uncommitted 。如下图所示,

    新开一个会话,查询一下事务隔离级别,如下图所示,

    现在把全局事务隔离级别设置为read uncommitted,如下图所示,

    把刚才的另一个会话窗口关闭再打开,查询发现也已经是未授权读取的级别,这里要注意的是:在隔离级别修改之前的会话,如果不重新关闭再打开,在这个老的会话范围内依然还是原来的级别。

     

    最佳实践

    阿里巴巴中间件负责人毕玄,在早年发表的《分布式Java应用  基础与实践》一书中强调,实践是最好的成长

    为了能够阐述的更加清楚一点,我们创建了一张表tb_user,同时两个字段id和name。下面就这张表作一下演示。演示过程中用到事务,我们就直接称为事务A、事务B、事务C....

    ①未授权读取。

    我们把全局事务隔离级别置为未授权读取read uncommitted。

    首先我们新开一个会话客户端A和B,同时,都开启事务,如下图示意,客户端B对原有的记录作更新操作,客户端A读取到了客户端B未提交的数据。

    小结:未授权读取,能够读取到其他没有提交的的事务所操作的结果,即未授权读取不能避免脏读。

    ②授权读取。

    我们把全局事务隔离级别置为未授权读取read committed。更改之后,当前会话并没有马上生效,需要重开一个窗口,也再一次证实了上面我提到的论点。

    我们新开一个会话客户端A和B,同时,都开启事务,如下图示意,客户端B对tb_user先做更新,再做新增操作,在客户端B事务已经提交的情况下,客户端A读取到了客户端B新增的数据,和更新的数据。

    小结:授权读取,只读取到其他事务已经提交的数据,能够避免脏读,但是不能避免可重复读取,上图客户端A中的事务在步骤2和7中的查询结果集不一致。

    ③可重复读取。

    我们把全局事务隔离级别置为未授权读取repeatable read。

    我们新开一个会话客户端A和B,同时,都开启事务,如下图示意,客户端B对tb_user先做更新,再做新增操作,在客户端B事务已经提交的情况下,客户端A没有取到了客户端B新增的数据,但是没有读取到更新的数据。

    小结:可重复读,可以解决脏读和可重复读,但是对于幻读,可能还是会存在。在上面的实例中,新增,有可能是能读取到的,注意这里的用词是可能,可能各个数据库的版本有所不同。

     ④串行化。

    串行化是最高级别的数据库事务隔离级别。

    我们把全局事务隔离级别置为未授权读取serializable。如下图在客户端A开始事务,同时在客户端B也开启事务,在客户端B中执行select *语句,不带where条件,发现客户端A中的update语句进入等待的状态。

    客户端A:

    客户端B:

     

    当客户端B执行commit;客户端A中的update语句立即执行。

    小结:串行化的级别能够解决脏读,可重复读,幻读的问题。只要多个事务存在共享资源的竞争时,就会进入到一个等待的状态,当然两个事务都是对同一个表select查询操作是没有关系的。

    注意:

    只有在资源竞争时,才会串行化。不同的表,则不受干扰,同一个表的不同记录,也不受干扰。

    1.客户端A开启事务执行select from tb_demo;客户端B开启事务执行update tb_user set name='123' where id=1;这两个事务互不干扰。

    2.客户端A开启事务执行select * from tb_user where where id=1;客户端B开启事务执行update tb_user t set t.name='老王' where id=2;两个事务互不干扰。

  • 相关阅读:
    Python的四种常见数据结构比较
    LeetCode Notes_#53 Maximum Subarray
    LeetCode Notes_#38 Count and Say
    LeetCode Notes_#6 Zigzag Conversion
    LeetCode Notes_#5 Longest Palindromic Substring
    《美国纽约摄影学院摄影教材》
    《艺术的故事》
    《Don't make me think》
    《Geospatial Data Science Techniques and Applications》
    《程序员的自我修养:链接、装载与库(完整版).pdf》
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/9736506.html
Copyright © 2020-2023  润新知