【问题标题】:What minimum isolation level is required for inserting unique text?插入唯一文本需要什么最低隔离级别?
【发布时间】:2016-10-18 19:53:31
【问题描述】:

我有一个带有文本列的表格,我想要一个唯一性保证。由于我不能对文本列设置唯一性约束,我想使用事务来包围我的插入以确保唯一性。

我的问题是:这个保证需要的最低隔离级别是多少?

【问题讨论】:

  • 投票关闭此问题作为重复。无论如何,没有事务行为强制唯一性,所以无论如何你都在追求错误的策略。
  • @BillKarwin 我不认为这个问题与如此标记的问题重复:其他问题的答案提供了替代解决方案(当然,应该使用),但仍然没有回答问的问题。要回答 OP,SERIALIZABLE 是您可以达到的最高级别,但仍不足以保证 all 情况下的唯一性。见kejser.org/race-condition-when-creating-unique-values
  • @BillKarwin 这与您发布的不是重复的。这个问题询问使文本唯一所需的隔离级别。另一个询问关于在文本列上创建唯一约束。

标签: mysql sql database isolation-level


【解决方案1】:

没有使用确保唯一性的事务。

为此使用UNIQUE 约束。

但是您不能创建任何超过 768 字节的索引,包括唯一索引。这意味着您不能对长字符串数据类型(如 TEXTVARCHAR 超过一定长度等)设置唯一约束。

您可以使用 前缀索引 使长字符串的前导部分唯一。

ALTER TABLE MyTable ADD UNIQUE KEY (textfield(255));

另一种确保唯一性的方法是在现有行中搜索要插入的值,只有在找不到时才插入新值。

但这要求您对表具有独占访问权限,以防止与另一个并发会话尝试插入相同值的竞争条件。

这也与事务隔离级别无关。即使SERIALIZABLE 隔离级别也无法帮助您避免竞争条件。阅读http://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html,上面写着:

[SERIALIZABLE] 类似于REPEATABLE READ,但如果禁用自动提交,InnoDB 会将所有普通的SELECT 语句隐式转换为SELECT ... LOCK IN SHARE MODE

因此,如果多个会话同时尝试读取表以检查重复值,则允许它们这样做,因为共享锁不会阻塞其他共享锁。然后他们可能全部决定插入新值是安全的,而你有重复。

要在读取表时获得排他锁,您需要明确使用SELECT ... FOR UPDATE。但是您可以在任何事务隔离级别中执行此操作。

【讨论】:

  • 只要确保我理解:SELECT unique_text_column FOR UPDATE 可以告诉我唯一文本是否确实存在?如果是这样,我是否不需要在事务中确保INSERT unique_text into table 语句在没有其他会话插入相同唯一文本的情况下运行?
  • 是的,您需要在单个事务中执行 SELECT 和随后的 INSERT,否则 SELECT FOR UPDATE 创建的锁将被释放。但这与隔离级别无关。
  • 但是隔离级别不会决定其他会话看到什么吗?即会话A开始trans,select unique_text_for updateINSERT unique_text into table。会话 B 开始事务并做同样的事情。在 B 的事务 READ_UNCOMMMITEDSerializable 中设置隔离级别会产生不同的结果吗?也就是说,READ_UNCOMMITED 不会看到 A 的插入。
  • 一旦会话 A 在一行(或该行所在的间隙)上获得了排他锁,会话 B 无法在同一行上为 SELECT FOR UPDATE 获取锁行,因为 A 有锁。无论任何一个会话中的任何事务隔离级别如何,这都是一样的。
  • 有道理,谢谢。我只是想确认我的理解,因为已经说了很多。如果所有会话都在事务中使用 SELECT 和随后的 INSERT 来插入文本列,那么这将保证该列的唯一性。对吗?
猜你喜欢
  • 2021-09-08
  • 2011-04-04
  • 1970-01-01
  • 2013-07-26
  • 2015-02-03
  • 2012-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多