处理长时间运行的Hibernate事务中的死锁

时间:2011-02-23 20:32:52

标签: multithreading hibernate transactions deadlock

我有一个Hibernate应用程序,可以使用相同的主键(分配)生成并发插入和更新(通过Session.saveOrUpdate)。这些事务有点长时间运行,平均可能是15秒(因为数据是从远程数据源收集的,并且在它进入时会持续存在)。我的数据库隔离级别设置为Read Committed,我正在使用MySQL和InnoDB。

问题是这种情况会导致过多的锁定等待,这是由于死锁或长事务造成的。这引出了几个问题:

  • 数据库引擎是否仅在提交事务时释放其锁定?
  • 如果是这种情况,我是否应该缩短交易时间?
  • 如果是这样,使用单独的读写事务是一个好习惯,其中写事务可以缩短并且只在我收集所有数据之后发生(我的事务长度大部分涉及收集远程数据) )。

编辑:

这是一个简单的测试,近似于我认为正在发生的事情。由于我正在处理长时间运行的事务,所以提交在第一次刷新后很久就会发生。所以为了说明我的情况,我离开了测试:

@Entity
static class Person {
    @Id
    Long id = Long.valueOf(1);
    @Version
    private int version;
}

@Test
public void updateTest() {
    for (int i = 0; i < 5; i++) {
        new Thread() {
            public void run() {
                Session s = sf.openSession();
                Transaction t = s.beginTransaction();
                Person p = new Person();
                s.saveOrUpdate(p);
                s.flush(); // Waits...
            }
        }.run();
    }
}

这期待产生的查询,等待第二个插入:

select id, version from person where id=?
insert into person (version, id) values (?, ?)
select id, version from person where id=?
insert into person (version, id) values (?, ?)

2 个答案:

答案 0 :(得分:1)

这是正确的,数据库仅在提交事务时才释放锁。由于您正在使用hibernate,因此可以使用乐观锁定,这会锁定数据库很长一段时间。从本质上讲,hibernate完成了你的建议,将读写部分分成单独的事务。在写入时,它检查内存中的数据是否未在数据库中同时更改。

答案 1 :(得分:0)

机会锁: 基本假设:更新冲突很少发生。 机械师:

  1. 使用版本字段读取数据集

  2. 更改数据集

  3. 更新数据集 3.1.使用当前版本字段和键读取数据集 如果你得到它,没有人改变记录。 应用下一个版本字段值。 更新记录。 如果没有收到,则记录已更改,向调用方返回适当的消息即可完成

  4. 插入不受影响,您也可以 无论如何都有一个单独的主键 或者您接受具有相同值的多个记录。 因此,上面给出的示例不是乐观锁定的情况。