如何使用Hibernate

时间:2018-06-07 20:10:16

标签: java database hibernate web-applications concurrency

在通过我的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锁?

我已经检查过,无法使用数据库中的约束来处理此问题

2 个答案:

答案 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的记录的患者。

在这种情况下,数据库将保证您不能将给定患者的多个记录插入表中。

您需要捕获唯一约束违规例外,并在住院治疗已存在的情况下做您想做的任何事情。