2023-03-23  阅读(53)
原文作者:一直不懂 原文地址:https://blog.csdn.net/shenchaohao12321/article/details/82798275

令人惊讶的是,大部分数据库系统都没有提供真正的隔离性,最初或许是因为系统实现者并没有真正理解这些问题。如今这些问题已经弄清楚了,但是数据库实现者在正确性和性能之间做了妥协。ISO和 ANIS SQL标准制定了四种事务隔离级别的标准,但是很少有数据库厂商遵循这些标准。比如 Oracle数据库就不支持READ UNCOMMITTED和 REPEATABLE READ的事务隔离级别。
SQL标准定义的四个隔离级别为:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

READ UNCOMMITTED称为浏览访问( browse access,仅仅针对事务顶的READ COMMITTED称为游标稳定(cursor stability)。 REPEATABLE READ是2.9999°的隔离,没有幻读的保护。 SERIALIZABLE称为隔离,或3°的隔离。SQL和SQL2标准的默认事务隔离级别是 SERIALIZABLE。
InnoDB存储引擎默认支持的隔离级别是 REPEATABLE READ,但是与标准SQL不同的是, InnoDB存储引擎在 REPEATABLE READ事务隔离级别下,使用Next-Key Lock锁的算法,因此避免幻读的产生。这与其他数据库系统(如 Microsoft SQL Server数据库〕是不同的。所以说, InnoDB存储引擎在默认的 REPEATABLE READ的事务隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的 SERIALIZABLE隔离级别。
隔离级别越低,事务请求的锁越少或保持锁的时间就越短。这也是为什么大多数数据库系统默认的事务隔离级别是READ COMMITTED。
据了解,大部分的用户质疑 SERIALIZABLE隔离级别带来的性能问题,但是根据 Jim gray在《Transaction Processing》一书中指出,两者的开销几乎是一样的,甚至SERIALIZABLE可能更优!因此在 InnoDB存储引擎中选择 REPEATABLE READ的事务隔离级别并不会有任何性能的损失。同样地,即使使用 READ COMMITTED的隔离级别,用户也不会得到性能的大幅度提升。
在 InnoDB存储引擎中,可以使用以下命令来设置当前会话或全局的事务隔离级别:

    SET [GLOBAL I SESSION] TRANSACTION ISOLATION LEVEL
    {
    READ UNCOMMITTED
    | READ COMMITTED
    | REPEATABLE READ
    | SERIALIZABLE
    }

如果想在 MySQL数据库启动时就设置事务的默认隔离级别,那就需要修改MySQL的配置文件,在[mysqld]中添加如下行:

    [mysqld]
    transaction-isolation=READ-COMMITTED

查看当前会话的事务隔离级别,可以使用:

    mysql> SELECT @@tx_isolation;
    +-----------------+
    | @@tx_isolation  |
    +-----------------+
    | REPEATABLE-READ |
    +-----------------+
    1 row in set, 1 warning (0.05 sec)

查看全局的事务隔离级别,可以使用

    mysql> SELECT @@global.tx_isolation;
    +-----------------------+
    | @@global.tx_isolation |
    +-----------------------+
    | REPEATABLE-READ       |
    +-----------------------+
    1 row in set, 1 warning (0.00 sec)

在SERIALIABLE的事务隔离级别, InnoDB存储引擎会对每个 SELECT语句后自动加上 LOCK IN SHARE MODE,即为每个读取操作加一个共享锁。因此在这个事务隔离级别下,读占用了锁,对一致性的非锁定读不再予以支持。这时,事务隔离级别 SERIALIZABLE符合数据库理论上的要求,即事务是well-formed的,并且是two-phrased的。有兴趣的读者可进一步研究因为 InnoDB存储引擎在 REPEATABLE READ隔离级别下就可以达到3°的隔离,因此一般不在本地事务中使用 SERIALIABLE的隔离级别。 SERIALIABLE的事务隔离级别主要用于 InnoDB存储引擎的分布式事务。
在 READ COMMITTED的事务隔离级别下,除了唯一性的约束检查及外键约束的检查需要 gap lock, InnoDB存储引擎不会使用gap lock的锁算法。但是使用这个事务隔离级别需要注意一些问题。首先,在 MySQL5.1中, READ COMMITTED事务隔离级别默认只能工作在 replication(复制)二进制日志为ROW的格式下。如果二进制日志工作在默认的 STATEMENT下,则会出现如下的错误:

    ERROR 1598(HY000): Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT

在 MySQL5.0版本以前,在不支持ROW格式的二进制日志时,也许有人知道通过将参数 innodb_locks_unsafe_for_binlog设置为1可以在二进制日志为 STATEMENT下使用 READ COMMITTED的事务隔离级别:

202303232333515841.png

202303232333525632.png

可以看到,数据产生了不一致。导致这个问题发生的原因有两点:

  • 在READ COMMITTED事务隔离级别下,事务没有使用 gap lock进行锁定,因此用户在会话B中可以在小于等于5的范围内插入一条记录;
  • STATEMENT格式记录的是 master上产生的SQL语句,因此在 master服务器上执行的顺序为先删后插,但是在 STATEMENT格式中记录的却是先插后删,逻辑顺序上产生了不一致。

要避免主从不一致的问题,只需解决上述问题中的一个就能保证数据的同步了。使用 READ REPEATABLE的事务隔离级别可以避免上述第一种情况的发生,也就避免了 master和 slave数据不一致问题的产生。
在 MySQL5.1版本之后,因为支持了ROW格式的二进制日志记录格式,避免了第二种情况的发生,所以可以放心使用READ COMMITTED的事务隔离级别。但即使不使用READ COMMITTED的事务隔离级别,也应该考虑将二进制日志的格式更换成ROW,因为这个格式记录的是行的变更,而不是简单的SQL语句,所以可以避免一些不同步现象的产生,进一步保证数据的同步。InnoDB存储引擎的创始人Heikkituuri也在http://bugs.mysql.com/bug.php?id=33210这个帖子中建议使用ROW格式的二进制日志。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文