钢筋之Mysql隐式提交和事务隔离级别的关系

2,785 阅读5分钟

前言

笔者自诩对Mysql的知识积累已经很不错了,现在看来不过是对CRUD操作比较熟悉罢了。

用了那么久的Mysql, 直到前几日才知道隐式提交和事务隔离级别的联系(内幕)。

那么,什么是隐式提交?

  • 顾名思义, 就是偷偷的提交事务(手动狗头)。

  • 讲道理在Mysql中, 开启一个事务后, 需要使用commit关键字进行提交事务,这种提交方式叫做显式提交。但是,我们在当前事务中输入某些语句之后, 会造成当前事务悄悄的提交,那么这种导致事务悄悄提交的情况, 我们称为隐藏提交。

  • 那么, 触发隐式提交的语句有哪些?

    • 使用createalterdelete语句去修改数据库、表、视图、存储过程等数据库对象的时候,就会隐式提交当前事务。

    • 使用ALTER USERCREATE USERDROP USERGRANTRENAME USERREVOKESET PASSWORD等语句, 也会触发隐式提交。

    • 当然有很多操作多会造成隐式提交, 经常使用的则是对数据库表的增、删、改操作。

      delete ... from
      update  set  from
      insert into ....
      

事务并发带来的问题

在笔者之前的知识体系中, 只是知道事务并发的概念,却不知是Mysql为什么会发生事务的并发。请原谅笔者, 到现在才知道事务的并发,是因为Mysql的C/S架构引起的…..

  • 事务并发诱因:

    讲道理, Mysql是一个C/S架构, 即客户端/服务器架构。所以,在使用过程中, 肯定会出现多个客户端访问服务器的场景。其中,每一个客户端向服务端发起访问, 可以称为建立一次数据库连接(session会话)。而每一个连接都可以发起数据库的事务。

    所以,不同的数据库连接之间的事务,有可能是并发执行的。

我们都知道,一旦产生并发有可能会对共享数据的状态,产生巨大的影响。

对于一次数据库连接而言,当两个事务同时操作同一种表的数据的时候, 可能会产生以下问题:

create table X (
  id int(10),
	name varchar(10)
);
insert into X values(1, '张三');
  • 肮读/写:一个事务能够读取/修改, 另一个事务未提交的数据。

  • 不可重复读:同一个事务内, 根据同一个条件对同一个行记录进行查询,但是搜出来的结果却不一致。

    企业微信20190808033854.png

    • 在数据库连接1中, 事务T1根据查询条件id = 1, 查询行记录name的值为张三, 且T1未提交。之后, 在另外一个数据库连接中, 根据条件id = 1, 把行记录name的值更新为李四。

      紧接着, 事务T1根据查询条件id = 1, 再次查询行记录name的值, 结果显示为李四。这种情况, 称为不可重复读。

      注意:在上图的右边更新语句, 触发了隐式提交。

  • 幻读:同一个事务内, 多次查询相同的条件返回的结果集不一样。

    企业微信幻读.png

    • 在数据库连接1中, 事务T1先根据查询H的所有记录, 这时返回结果为张三。之后, 另外一个事务T2对表插入李四这条记录。此时事务T1再次查询H表的所有记录, 返回的结果为张三和李四, 此时发生这种情况称为幻读。

写到这里, 并发带来的问题差不多描述完了。

那么, 如何解决事务并发所带来的问题呢?事务的隔离级别, 了解一下!

事务的隔离级别

如果, 在事务隔离性方面, 直接一杆子打死。要求,所有的并发事务都必须串行化执行(一个接一个, 即不允许并发), 那么这样做会造成执行效率过低。

所以, 在性能和隔离性方面, 我们需要一种折中的办法, 即允许并发问题的出现(脏读、不可重复读、幻读), 根据出现的问题, 设置隔离强度。

在SQL标准中,具有四种隔离级别, 分别是读已提交读未提交可重复读可串行化

  • READ UNCOMMITTED:可能发生脏读、不可重读读、幻读
  • READ COMMITTED:解决脏读, 可能会发生不可重复读、幻读
  • REPEATABLE READ:解决脏读、不可重复读, 可能发生幻读
  • SERIALIZABLE:串行化执行, 并不会发生并发问题。即, 解决脏读, 不可重复读、幻读。

上述的四种隔离级别, 是所有数据库通用的标准。因为不同数据库, 隔离级别的支持情况并不一样。

但是, Mysq包含且支持四种上述的四种隔离级别。

唯一不同的是, Mysql在可重复读(REPEATABLE READ)的隔离级别下, 是可以解决幻读问题。所以, Mysql的默认隔离级别为可重复读!

总结

  • 根据事务并发带来的问题的严重性, 可以适度选择相应的隔离级别来解决。

  • 脏写是并发事务带来的最最最严重的问题, 所以四种隔离级别中, 直接禁止脏写的出现。

  • 在Mysql标准中的可重复读, 是可以解决幻读问题。

  • 幻读主要强调, 使用同一个条件多次进行查询后, 返回之前查询结果中, 没有获取到的记录。

    比如这种场景, 算不算幻读?

    • 事务T1, 第一次查询得到结果集合:A、B、C、D
    • 期间, 事务T2, 删除了C、D记录
    • 事务T2, 第二次查询得到结果集合:A、B

    其实, 上述情况属于不可重复读, 而不是幻读。