Multithreading 处理长时间运行的Hibernate事务中的死锁
我有一个Hibernate应用程序,它可以(通过Multithreading 处理长时间运行的Hibernate事务中的死锁,multithreading,hibernate,transactions,deadlock,Multithreading,Hibernate,Transactions,Deadlock,我有一个Hibernate应用程序,它可以(通过Session.saveOrUpdate)对具有相同主键的记录进行并发插入和更新,主键是分配的。这些事务运行时间较长,平均可能为15秒(因为数据是从远程源收集的,并在数据进入时持久化)。我的DB隔离级别设置为Read Committed,我使用的是MySQL和InnoDB 问题是,此场景会创建过多的锁等待超时,这可能是由于死锁或长事务造成的。这就引出了几个问题: 数据库引擎是否仅在提交事务时释放其锁 如果是这样,我是否应该缩短我的交易时间 如果是
Session.saveOrUpdate
)对具有相同主键的记录进行并发插入和更新,主键是分配的。这些事务运行时间较长,平均可能为15秒(因为数据是从远程源收集的,并在数据进入时持久化)。我的DB隔离级别设置为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();
}
}
没错,只有在提交事务时,数据库才会释放锁。因为您使用的是hibernate,所以可以使用乐观锁定,它会长时间锁定数据库。本质上,hibernate按照您的建议执行,将读写部分分离为单独的事务。写入时,它检查内存中的数据在数据库中是否没有同时更改
据我所知,使用Hibernate启用乐观锁定只需要在实体中的int上抛出@Version注释。我确实尝试过上面描述的场景,但没有任何好处。请参阅我在原始帖子中添加的测试,该测试使用乐观版本控制来重现场景。我讨厌在5年后遇到完全相同的问题时遇到这些类型的问题,我看不到答案:(
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 (?, ?)