【问题标题】:MySQL interprets SERIALIZABLE less strenuously than PostgreSQL. Is it correct?MySQL 对 SERIALIZABLE 的解释不如 PostgreSQL 那样费力。这是正确的吗?
【发布时间】:2018-08-31 01:20:55
【问题描述】:

当使用SERIALIZABLE 事务来实现仅在数据库中不存在值的情况下将值插入数据库的模式时,我观察到 MySQL 和 PostgreSQL 在SERIALIZABLE 隔离级别的定义方面存在显着差异。

考虑下表:

CREATE TABLE person (
    person_id INTEGER PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR NOT NULL
);

以下插入代码在两个连接上同时运行:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT person_id FROM person WHERE name = 'Bob Ross';
-- sync point: both transactions should run through here before proceeding to
-- demonstrate the effect

-- 0 results, so we will insert
INSERT INTO person (name) VALUES ('Bob Ross');
SELECT last_insert_id();
COMMIT;

在 PostgreSQL 中(经过适当的 SQL 翻译后),效果如我所料:只有一个事务可以成功提交。这与我对 PostgreSQL 描述的 SERIALIZABLE 的理解以及引用 ANSI 标准的其他来源一致:存在会产生相同效果的事务的串行执行。这两个事务没有串行执行返回 0 结果进行搜索然后添加条目。

在 MySQL 5.7 中,两个事务都成功并且表中有 2 个“Bob Ross”条目。 MySQL 文档对SERIALIZABLE 的定义是禁止脏读、不可重复读和幻读;它没有提到串行执行的存在。

由于其保守的锁定策略,SQLite 至少在其默认模式下也正确地阻止了双重插入。

我的问题:MySQL 在这种情况下的行为是正确的,还是因为允许这些事务都成功而违反了 SQL 标准?我怀疑答案可能取决于“效果”的定义——对于两个具有相同效果的串行执行而言,从第一个 SELECT 观察到一个空结果集是否算作“效果”?

另外几个 cmets 来帮助解决这个问题:

  • 我知道我可以通过首先使用ON CONFLICT IGNORE 进行插入,然后进行选择来在 MySQL 中实现所需的行为。我试图理解为什么等效的标准 SQL 在两个引擎中没有表现出相同的行为。
  • 我知道我也可以通过在name 字段上设置唯一约束来修复它,无论如何这可以说是一个更好的数据模型。但核心问题仍然存在:为什么这些交易都成功了?

【问题讨论】:

  • 你是如何进行测试的?您也不应该能够为 MySQL 获得 2 个 bob rosses。一个事务将在insert-step 处等待(如果另一个事务的select 在此之前发生),另一个事务将在尝试插入时因死锁而回滚(这对于“可序列化”来说很好) )。 MySQL 实际上与其他数据库的不同之处在于它不会在(第二个)select 等待(这将产生更少的死锁但更多的等待 - 但这实际上并不违反“可序列化”)。旁注:表名和列名与查询不匹配。
  • 我打开了两个连接,并运行了相关查询。我将两个连接都带到了指定点(在插入之前),然后插入 1,插入 2,提交 1,提交 2。MySQL 提交了两个事务,随后的查询找到了 2 个 Bob Ross 条目。
  • 我在 rextester part 1part 2 上给你做了一个测试。打开两个链接,运行第 1 部分,在它运行的 5 秒内(它使用sleep 暂停执行)运行第 2 部分。预期结果:应该导致死锁。如果您可以验证这是否发生在您身上,那么第二个问题是您的设置有什么不同。我不知道你对 MySQL 有多熟悉(所以你可能已经检查过这个),但最简单的解释是你使用了不支持事务的 MyISAM 引擎(使用show create table person 来检查)。
  • 我会说 查询 不正确。仅当行不存在时才插入行的典型方法是 INSERT .. SELECT 'a','b' WHERE NOT EXISTS 或类似的变体。使用 transaction 来实现相同的效果并不能很好地扩展
  • @MichaelEkstrand 仔细检查一下,您的 MySQL 表是使用 InnoDB 还是 MyISAM ?(MyISAM 表不是事务性的)

标签: mysql sql postgresql standards transaction-isolation


【解决方案1】:

SQL 标准在 4.35.4 SQL 事务的隔离级别(强调我的)一章中说:

在隔离级别 SERIALIZABLE 的并发 SQL 事务的执行保证是可序列化的。 可串行执行被定义为并行执行 SQL 事务的操作的执行,其产生与那些相同 SQL 事务的某些串行执行相同的效果。串行执行是其中每个 SQL -事务在下一个 SQL 事务开始之前执行完成。

再往下一点,它继续混淆问题:

隔离级别指定并发 SQL 事务执行期间可能发生的现象类型。可能出现以下现象:

[跳过P1(“脏读”)P2(“不可重复读”)的定义P3(“幻影”​​)]

四个隔离级别保证每个 SQL 事务将完全执行或根本不执行,并且不会丢失任何更新。对于现象P1P2P3,隔离级别不同。表 8,“SQL 事务隔离级别和三种现象”指定了可能的和不可能的现象 对于给定的隔离级别是可能的。

+------------------+--------------+--------------+--------------+ 
| Level            | P1           | P2           | P3           |
+------------------+--------------+--------------+--------------+
| READ UNCOMMITTED | Possible     | Possible     | Possible     |
+------------------+--------------+--------------+--------------+
| READ COMMITTED   | Not Possible | Possible     | Possible     |
+------------------+--------------+--------------+--------------+
| REPEATABLE READ  | Not Possible | Not Possible | Possible     |
+------------------+--------------+--------------+--------------+
| SERIALIZABLE     | Not Possible | Not Possible | Not Possible |
+------------------+--------------+--------------+--------------+

注意 53 — 在隔离级别 SERIALIZABLE 执行的 SQL 事务排除这些现象是要求此类事务可序列化的结果。

这个措辞带来了不幸的后果,即许多实现者认为排除直接读取、不可重复读取和幻读就足以正确实现SERIALIZABLE 隔离级别,尽管注释澄清了这是不是定义,而是定义的结果

所以我认为 MySQL 是错误的,但它并不孤单:Oracle 数据库以同样的方式解释 SERIALIZABLE

【讨论】:

    【解决方案2】:

    我无法在 MySQL 5.7 中重现这一点。其他事务总是报错:

    ERROR 1213 (40001):尝试获取锁时发现死锁;

    原因是 SELECT 不使用 WHERE 部分中的索引列,因此它将 s-locks 设置为它找到的每一行,gap-s-lock 设置为找到的行之间的每个间隙,next-key 锁定为正找到最后一行后的无穷大。所以在这种情况下并发 INSERT 是不可能的。

    您得到结果的一个可能原因可能是:

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    

    它只为下一个事务设置隔离级别。如果在此之后您甚至执行了一次 SELECT,隔离级别就会恢复正常(可重复读取)。

    更好用

    SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 2011-05-24
      相关资源
      最近更新 更多