JBDC - 跨并发线程以原子方式执行SELECT和INSERT

时间:2012-03-06 07:44:11

标签: java multithreading jdbc

我在网上搜索了一些简单的例子,但无济于事。我需要在Java中使用JDBC作为原子单元运行selectinsert操作。

实际上我需要做以下事情:

  1. 从用户中选择代码
  2. 浏览所有代码,直到找到未使用的代码(因为可以删除用户,可能会在范围中间提供代码)
  3. 使用该可用代码插入新用户
  4. 这通常是一个简单的操作,但由于我的应用程序是多线程的,我不知道如何解决这个问题。因为同时运行的并发线程可以尝试使用相同的代码值插入。

    我可以考虑使用几种解决方法或黑客来完成这项工作,但一般来说如何锁定表以使此操作成为原子?我见过的大多数都涉及行锁,但由于我没有更新,我不知道这是如何适用的。

3 个答案:

答案 0 :(得分:1)

这完全是在SQL中完成的一个难题。任何解决方案都会遇到竞争条件问题。如果我要在SQL中完全使用SQL,我会使用已删除的代码表。当用户随后被删除时,您将使用某些服务将其代码添加到已删除的表中。如果删除的代码表为空,则线程将使用序列号来获取其新代码。从已删除的代码中获取代码需要位于synchronized块中,因为get和then set nature具有多个SQL操作。我不认为SQL事务会对那里有所帮助。它们可以保持数据一致,但如果两个线程使用相同的代码,那么两个提交中的一个将引发异常。

我认为更好,更快的机制是让一个单独的线程管理这些删除的代码。它可以将其写入数据库,但也保留BlockingQueue个已删除的代码供其他线程使用。如果必须没有漏洞并且您担心崩溃,则需要通过在启动时查询用户表来验证可用漏洞列表。它不需要同步或执行任何SQL事务,因为它只会从已删除的代码表中删除。

希望这有帮助。

答案 1 :(得分:1)

我倾向于将逻辑放在存储过程中。使用“select for update”锁定,然后提交解锁。

您可以在insert语句中添加一个过滤器,并在客户端重试逻辑,我想:

  • 确定可用代码(建议代码)
  • 使用过滤器执行插入,确定executeUpdate结果中的行数(0表示并发线程获取此代码,再试一次)

插入内容会沿着这些行显示,其中3是您的新ID,'Joe'是您的新用户,并建议编码您认为可用的那个:

INSERT INTO users
  SELECT 3, :proposedCode, 'Joe' 
    FROM dual
    WHERE :proposedCode NOT IN (SELECT code FROM users)

答案 2 :(得分:1)

怎么样:

insert into usertable (
  id, 
  code, 
  name
) values (
  user_id_sequence.nextval,
  (
      select min(newcode) 
        from usertable, (
           select level newcode 
             from dual 
          connect by level <= (select max(code)+1 from usertable))
       where not exists (select 1 from usertable where code = newcode)
  ),
  'mynewusername'
)

编辑:

更改为max(code)+ 1,因此如果没有可用的间隙,则可以使用新代码。