6

我正在寻找一种从 Java 6 应用程序中处理数据库死锁的好策略;几个并行线程可能同时写入同一个表。如果数据库 (Ingres RDMBS) 检测到死锁,它将随机终止其中一个会话。

考虑到以下要求,什么是处理死锁情况的可接受技术?

  • 总经过时间应保持尽可能小
  • 终止会话将导致显着(可测量的)回滚
  • 时间线程无法相互
    通信,即策略应该是自治的

到目前为止,我想出的策略是这样的:

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
    try {
        //insert loads of records in table 'x'
        success = true;
    } catch (ConcurrencyFailureException e) {
        attempts++;
        success = false;
        delayMs = 1000*attempts+random.nextInt(1000*attempts);

        try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
        }
    }
} while (!success);

它可以以任何方式改进吗?例如等待固定数量(幻数)的秒数。是否有不同的策略可以产生更好的结果?

注意:将使用几种数据库级技术来确保死锁在实践中非常罕见。此外,应用程序将尝试避免调度同时写入同一个表的线程。上述情况只是“最坏的情况”。

注意:插入记录的表组织为堆分区表,没有索引;每个线程都会在自己的分区中插入记录。

4

5 回答 5

11

一种常用的方法是某种形式的指数回退。而不是你的1000*attempts+random方法,使延迟成为尝试次数的指数函数。这可确保在前一两次尝试中将延迟降至最低,在这种情况下,您可能会陷入僵局,但稍后会在很明显连接确实拥塞时给您带来更大的延迟。

当然,另一种方法是尝试安排您的数据库访问,以便不太可能发生死锁。但是如果不知道您的查询做什么(以及如何以及何时执行),就不可能说是否可以做到

于 2009-12-08T11:19:07.820 回答
1

我们就是这样做的。循环并重试事务,直到完成。

我们没有搞乱随机延迟。

此外,我们在try块内进行了提交,并在异常处理程序中进行了回滚。

当您有多个可锁定资源和多个并发事务时,死锁是不可避免的。这是锁竞争的逻辑结果。

如果您避免争用锁(即悲观的表级锁定),那么您也倾向于防止并发。如果可以定义不争锁的事务,就可以避免死锁。然而,对同一张表的并发访问几乎就是死锁的定义。

加载时,插入(特别是在 HEAP 表中)可以(通常)并行进行,而不会出现很多争用问题。如果您延迟构建索引,则在插入期间不会进行其他更新。

因此,您可以通过删除索引、将组织更改为堆、加载多个并发进程(或线程,拥有多个进程通常更快)然后构建索引(并可能重新组织表)来避免,你也许可以避免死锁。

进行更新或删除时,帮助不大。

于 2009-12-08T11:17:39.383 回答
1

如果您不需要同时访问数据库,一个简单的解决方案可能是删除它并使用任务处理队列来更新数据库,通过队列对数据库进行序列化访问。我意识到这将为您的应用程序引入一个异步元素,因此不适用于大多数用户启动的应用程序或在线 Web 应用程序,但对于批处理/离线类型的应用程序可能值得考虑(我意识到可能不是您想要的答案虽然)。

于 2009-12-08T11:18:10.443 回答
0

对于像 Ingres 这样的数据库,您总是会遇到一些死锁,因此您必须假设任何插入、更新或删除都将失败并有一个重试策略(如您的示例中所示)。您应该设计您的数据库,以使争用最小化并且死锁很少发生。如果您在多次重试后仍不断出现事务失败,那么这表明您必须进行一些重大的数据库重新设计(或转移到像 Oracle 这样的系统,通常可以通过适当的使用来设计应用程序以避免死锁行级锁定)。

于 2009-12-08T11:19:36.023 回答
0

这怎么样 ?

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
try {
     synchronized(ClassName.class) {
         //insert loads of records in table 'x'
      }

    success = true;
} catch (ConcurrencyFailureException e) {
    attempts++;
    success = false;
    delayMs = 1000*attempts+random.nextInt(1000*attempts);

    try {
                    Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
    }
  }
} while (!success);
于 2009-12-08T11:22:33.547 回答