Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程-避免和处理数据库死锁_Java_Algorithm_Database Deadlocks_Scenarios_Ingres - Fatal编程技术网

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

Java 多线程-避免和处理数据库死锁,java,algorithm,database-deadlocks,scenarios,ingres,Java,Algorithm,Database Deadlocks,Scenarios,Ingres,我正在寻找一种处理Java6应用程序中数据库死锁的好策略;多个并行线程可能同时写入同一个表。如果检测到死锁,数据库(Ingres RDMBS)将随机终止其中一个会话 考虑到以下要求,处理死锁情况的可接受技术是什么 应保留总运行时间 尽可能小 终止会话将导致 显著(可测量)回滚 时间线程无法访问 相互沟通,即 战略应该是自主的 到目前为止,我提出的策略大致如下: short attempts = 0; boolean success = false; long delayMs = 0; Ra

我正在寻找一种处理Java6应用程序中数据库死锁的好策略;多个并行线程可能同时写入同一个表。如果检测到死锁,数据库(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);
有什么办法可以改进吗?e、 g.等待固定的秒数(幻数)。 是否有不同的策略可以产生更好的结果

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


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

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

我们没有随意拖延

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

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

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

加载时,插入(特别是在堆表中)可以(通常)并行进行,而不会出现许多争用问题。如果您延迟构建索引,那么在插入过程中不会有其他更新

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


在执行更新或删除时,没有太多帮助。

如果您不需要同时访问数据库,一个简单的解决方案可能是删除它并使用任务处理队列来更新数据库,通过队列序列化对数据库的访问。我意识到这将为您的应用程序引入异步元素,因此不适用于大多数用户启动的应用程序或在线web应用程序,但对于批处理/离线类型的应用程序可能值得考虑(我意识到可能不是您想要的答案)一种常用的方法是某种形式的指数退避。将延迟设置为尝试次数的指数函数,而不是
1000*次尝试+随机
aproach。这确保了在第一次或第二次尝试中的最小延迟,在这种情况下,您可能会因为死锁而运气不佳,但在以后很明显连接确实拥挤时,会给您带来更大的延迟


当然,另一种方法是尝试安排数据库访问,以减少死锁的发生。但是,如果不知道您的查询是做什么的(以及如何执行,以及何时执行),就不可能确定使用诸如Ingres之类的数据库是否可以做到这一点,您总是会遇到一些死锁,因此您必须假设任何插入、更新或删除操作都会失败,并且有一个适当的重试策略(如您的示例所示)。 您应该设计数据库,使争用最小化,死锁很少发生。如果您在多次重试后仍不断遇到事务失败的情况,那么这表明您必须进行一些重大的数据库重新设计(或者转移到像Oracle这样的系统,在该系统中,通常可以通过适当使用行级锁定来设计应用程序以避免死锁)。

这是怎么回事

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);

在我的模拟(20个线程)中,零延迟将触发大量死锁;一个大的延迟实际上会显著改善总的运行时间。autocommit设置为on,但数据库死锁也会涉及自动提交rollback@Adrian:我们有相当复杂的错误处理,因此我们进行了回滚“只是为了确保”。我们也在使用C语言,所以这是一个“虚拟的例外”。最后,我们让一些C/Ingres N00B进行编码,以防它们隐藏了一些逻辑错误。@Adrian:在我们的实际实践中,没有延迟的存在并没有任何实际的区别。负载沉重的操作系统引入了自己的随机延迟。YMMV。我不是在辩论你的模拟。我告诉你我们做了什么。我们没有处理随机延迟。@S.Lott我们确实使用了一个没有IndexeSponential函数的堆表(实际上是一个分区堆表),听起来不错-我将尝试模拟它!正如我在说明中提到的,应用程序设计的目的是避免死锁,包括有利地安排数据库访问。但不能保证在紧急情况下会发生大量死锁。您能否为您提到的“指数退避”技术提供技术参考?它通常用于网络协议中以避免拥塞。查看维基文章:但基本思想很简单。您只需使用某种指数函数来确定每次重试时的延迟。具体细节可以从b