在通过我的Web应用程序插入数据时,我有一个控制并发性的问题。
背景:我有3个表(X,Y和Z)记录患者的住院情况。患者不能有多于一个的积极住院治疗。
目前我的应用程序在数据库中的住院INSERT之前进行验证,检查患者是否已经住院。
但是,当两个或更多用户试图同时接纳同一患者时,此验证不起作用。
我现在做的事情:
1 - verify if patient is already hospitalized (SELECT in table X)
If not:
begin transaction A;
2 - INSERT in table X;
3 - INSERT in table Y;
4 - INSERT in table Z;
end transaction A;
正如我之前提到的,1中的验证试图避免患者住院两次或更多次。但是,如果两个(或更多)用户试图同时接纳同一患者,则无效。
也许我可以使用可以锁定SELECT语句的东西,直到事务A完成为止。通过这种方式,SELECT将识别患者在执行时已经注册。
我想在数据库中使用PostgreSQL中的EXPLICITING LOCKING来解决这个问题。根据文档,我可以使用ACCESS EXCLUSIVE锁定模式执行类似的操作(因为它是唯一可以锁定select语句的模式)。
但是如何在Hibernate中实现这个ACCESS EXCLUSIVE锁?
我已经检查过,无法使用数据库中的约束来处理此问题
答案 0 :(得分:0)
你有什么尝试?你的问题提到了postgres。我查看了他们的文档here。如果要从数据库末端解决问题,可以按照规范中的定义尝试 Serializable Isolation Level 的事务。
从他们的文档中,使用此隔离级别不可能进行脏读,幻读和不可重复读。
或者,如果要解决Java问题,可以围绕所需的类创建同步服务包装,以便提供适当的同步逻辑。所以,如果你有
public interface MyService {
public void hospitalize(Patient patient) throws Exception;
// etc
}
带
public class MyServiceImpl implements MyService {
@Transactional
public void hospitalize(Patient patient) throws Exception {
// your logic
}
}
和
public MyServiceSerialImpl extends MyServiceImpl {
@Override
@Transactional
public void hospitalize(Patient patient) throws Exception {
// ...
synchronized (lock) {
super.hospitalize(patient);
}
// ...
}
private final Object lock = new Object();
}
或在整个方法或类似的东西上同步。
修改强>
正如Roman Konoval在评论中指出的那样,如果有多个应用程序,一个集群,一个以上的jvm等,与Java的同步解决方案将无济于事。数据库是哪里的你需要工作。
答案 1 :(得分:0)
为了确保单个患者不能住院两次,您需要在X(和/或Y,Z)对患者的参考字段中添加唯一约束(我假设已经存在像patient_id
这样的字段,至少在其中一个表中,否则如何引用插入X,Y和Z的记录的患者。
在这种情况下,数据库将保证您不能将给定患者的多个记录插入表中。
您需要捕获唯一约束违规例外,并在住院治疗已存在的情况下做您想做的任何事情。