用于多线程应用程序的Hibernate getOrCreate模式

时间:2013-08-13 11:23:57

标签: java hibernate

我已经搜索了一段时间,但还没有找到我想要做的例子。


我们有一个将被大量使用的API。其中一个操作是创建一个新的Client域对象。每个Client的名称都是唯一的。

在以下代码中,我们按名称读取客户端。如果它不存在,我们尝试创建它。由于2个线程可能同时尝试创建同一个客户端,我们捕获ConstraintException然后再进行另一次查找,在我们面前加入另一个线程:

@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false, isolation = Isolation.READ_COMMITTED)
public Client getOrCreate(String name) {
    DetachedCriteria query = DetachedCriteria.forClass(Client.class).add(Restrictions.eq("name", name));

    Client client = entityDao.findSingle(Client.class, query);

    if (client == null) {
        client = new Client();
        client.setName(name);
        try {
            entityDao.save(client);
        } catch (ConstraintViolationException e) {
            client = entityService.findSingle(Client.class, query);
        }
    }
    return client;
}

Hibernate抱怨这段代码,因为在异常中我们试图使用一个异常中涉及的会话:

org.hibernate.AssertionFailure: null id in com.mydomain.Client entry (don't flush the Session after an exception occurs)

是否有标准模式或方法来完成我在Hibernate中尝试做的事情?

1 个答案:

答案 0 :(得分:2)

您只需要移动catch并重试事务,以便使用新的事务(和会话):

Client client;
try {
    client = clientService.getOrCreate(name);
}
catch (ConstraintViolationException e) {
    client = clientService.getOrCreate(name);
}

@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false, isolation = Isolation.READ_COMMITTED)
public Client getOrCreate(String name) {
    DetachedCriteria query =
        DetachedCriteria.forClass(Client.class).add(Restrictions.eq("name", name));

    Client client = entityDao.findSingle(Client.class, query);

    if (client == null) {
        client = new Client();
        client.setName(name);
        entityDao.save(client);
    }
    return client;
}