1

我需要同时在四个无数线程中执行以下操作(嗯,可能更接近 2 个线程,但无论哪种方式......):如果某某不存在,请插入它。

目前,该应用程序说:

select rows from the db
if row count == 0,
    do some stuff
    insert a row

我有一种情况,它同时在 2 个单独的线程中运行。这样,两个线程可以(实际上到目前为止每次都这样做)在任一线程插入行之前检查现有行;因此我们有重复的行。这是不好的。

我能想到的所有算法都不尽如人意。

例如,如果我这样做:

open tx
insert a row
select rows
if row count > 2, rollback
else commit

当事务使用READ_COMMITTED隔离时,一个线程将看不到另一个线程的插入行,并且可能出现重复。通过READ_UNCOMMITTED隔离,每个线程都可以看到另一个线程的行,并且两者都会回滚。我想如果我使用MERGE语句而不是插入然后选择(反之亦然),我会遇到同样的问题。

当上述算法同时执行时,是否有一种算法可以用来保证恰好插入 1 行?FWIW,我在 Spring 中使用 DB2、mybatis 和基于 xml 的 tx 管理,但如果可能的话,我很乐意从其他方面进行翻译。

在并发方面我是新手,所以如果这个问题揭示了您所知道的书籍或文章所弥补的无知,请分享。

编辑:

上面的插入语句是懒惰地授予用户一些东西,如果他们没有的话。在这种情况下,唯一性约束将是合适的。然而,在应用程序的其他地方,它是不合适的。:(

我很快就会使这个例子更具体一些,这样更容易理解。

4

4 回答 4

4

我会创建一个唯一性约束并使用 ReadCommitted。这样,如果第二个线程尝试插入一个 dup,它会回滚,但初始插入有效。

于 2012-10-29T21:16:44.410 回答
1

我们能找到的唯一解决方案是在可序列化事务中发出“如果不存在符合条件的记录则插入”命令。如果不存在满足某些条件的记录,则 SQL 本身可以是插入记录的任何东西(例如,MERGE 会起作用)。在这种情况下,一旦一个线程检查是否存在满足所选语句标准的行,则在 tx 完成之前,没有其他线程可以插入任何满足该标准的内容。为了性能,我们为合并操作打开了一个新的 tx,并在完成后立即提交。

我们使用 DB2 和 Oracle 成功地测试了这个解决方案。

于 2012-12-16T18:08:07.470 回答
0

我们做类似的事情。因为我们不想锁定表,所以我们使用乐观并发和唯一性约束。

  1. 由于并发性,第一个会烧伤你的条件是在两个单独的线程中两次插入相同的东西。其他人提到的解决方案是在您的架构中包含唯一性约束。如果您有一个列可以为空的复合约束,这可能会很棘手。看到这个激烈的论点:http ://bugs.mysql.com/bug.php?id=8173所以你可能需要一个额外的列用于唯一性约束。

  2. 第二个可能会让您感到痛苦的情况是您需要对数据进行更新(例如递增一或某事)。在这种情况下,我们使用 hibernate 支持的乐观并发及其行版本控制。查看http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html#transactions-optimistic。不确定mybatis是否有类似的东西,但你可以手动编写相同的东西。如果你的线程确实有冲突,一个会失败。对我们来说,我们都需要成功,所以如果发生冲突,失败的线程将重试操作(通过重新读取、重新处理和重新写入数据)。在这种情况下,我们做一些类似于以太网工作方式(或任何其他基于冲突的协议/操作)的事情,即尝试,如果失败,以某种方式退避并重试。

HTH。

于 2012-10-30T00:46:45.937 回答
0

我建议尝试

MERGE

SQL 语句。它能够插入在单个语句中不存在的行。

于 2012-11-02T01:18:32.390 回答