多线程 - 避免和处理数据库死锁

Adr*_*ian 5 java algorithm ingres scenarios database-deadlocks

我正在寻找一个从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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

jal*_*alf 11

常用的方法是某种形式的指数退避.而不是你的方法1000*attempts+random,使延迟成为尝试次数的指数函数.这可以确保在前一次或两次尝试中的最小延迟,在这种情况下,您可能只是运气不好而导致死锁,但在以后很明显连接确实很拥挤时会给您带来更大的延迟.

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

  • 它通常用于网络协议以避免拥塞.查看维基文章:http://en.wikipedia.org/wiki/Exponential_backoff但基本思路很简单.您只需使用某种指数函数来确定每次重试尝试的延迟.确切的细节可以调整,以满足您的目的.当然,最简单的可能实现是延迟2 ^ n ms,其中n是到目前为止的重试次数.但也许你认为开始增长太慢,或开始太低,或增长得太快.然后你只需添加一个乘数,或者向n添加一些东西 (2认同)