2011-05-17 57 views
7

我遇到了一个问题。我有一个Hibernate应用程序,它将XML文件中的数据加载到并发模式的表中。某些部分数据可能相同,可能从不同的线程插入。每个线程都在自己的长时间交易中工作。有两个或更多步骤尝试提交事务时存在问题。例如两个线程插入记录到表城市,其中有名称字段的限制。这意味着在flush()或commit()上发生ConstraintViolationException。我想自动处理这些冲突,并希望用旧的已插入对象替换新的问题对象。这可能吗?我在Hibernate中查看saveOrUpdate()和乐观版本控制。Hibernate并发插入

+0

您好,如果您将问题分享给您的解决方案,我会很高兴。看起来下面是正确的答案,但简单的解释应该更方便。非常感谢。 – Javatar 2012-02-25 18:04:19

回答

1

我假设你使用MVCC-based DBMS之一。

如果事务隔离级别不高于READ COMMITTED,可以通过在插入新行之前发出一个查询来检查是否存在具有相同name的城市的查询来降低冲突概率。

请注意,saveOrUpdate()不能帮助这里,因为name不是主键。还要注意,根本不能防止冲突(至少不使用某些DBMS特有的功能),因为基本上它是write skew anomaly的示例,这在基于MVCC的DBMS中无法防止。另外,如果导入XML文件的原子性并不重要,则可以将长事务分解成几个较短的事务,并且在违反约束的情况下简单地重试它们。

+0

谢谢,分解交易是一个好主意。我认为,在并发情况下,城市对象的存在并不能起作用。总会有碰撞的机会。同意saveOrUpdate()已经检查过它。 – 2011-05-17 13:50:39

+0

对不起,您的意思是使用READ UNCOMMITTED并检查存在?我认为它可以帮助。至少未被记录的记录是在交易中共享的,并且在没有记录的会话中进行存在检查并不昂贵。 – 2011-05-17 14:10:37

0

在这样的情况下,我们使用'insertOrUpdate()'方法的约定和下面的一般流程。该交易是在返回时由'insertOrUpdate()'方法的调用者承诺的:

public MyHibernateObject insertOrUpdate(MyHibernateObject newObj, Session s) { 
    String name = newObj.getCityName(); 
    MyHibernateObject existingObj = getByCityName(name, s); 
    if (existingObj == null) { 
     s.saveOrUpdate(newObj); 
     return newObj; 
    } else { 
     existing.copyImportantFields(newObj); 
     s.saveOrUpdate(existing); 
     return existing; 
    } 
}