9

I faced a problem. I have an App with Hibernate that loads data from XML files into tables in concurrent mode. Some part of data could be same and could be inserted from differnet threads. Each thread works in its own long-play transaction. There's an issue when two or more treads try to commit transaction. For example two threads inserted records into table City that has constraint on NAME field. It means that ConstraintViolationException occurs on flush() or commit(). I want to automatically handle this collisions and want new problem objects to be replaced with older already inserted objects. Is this possible? I look at saveOrUpdate() and optimistic version control in Hibernate.

1
  • Hello, i would be glad if you share your solution to that problem. It seems below is the correct answer, however a brief explanation should be more convenient. Thanks a lot. Commented Feb 25, 2012 at 18:04

3 Answers 3

2

I assume that you use one of MVCC-based DBMS.

If transaction isolation level is not higher than READ COMMITTED, you can reduce probability of conflict by issuing a query to check for existence of Cities with the same name before inserting the new one.

Note that saveOrUpdate() can't help here, since name is not a primary key. Also note that you cannot prevent conflict at all (at least without using some DBMS-specific features), since basically it's an example of write skew anomaly, which can't be prevented in MVCC-based DBMS.

Also, if atomicity of importing XML file is not critical, you can break long transaction into several shorter ones, and simple retry them in a case of constraint violation.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, it's a good idea to break down transaction. I think cheking existance of City object can't help in concurrent scenario. There is always a chance to get a collision. Agree with saveOrUpdate() already checked it.
Sorry, you mean use READ UNCOMMITTED and checking existance? I think it can helps. At least uncommited records are shared among transactions and it's not so expensive to do existance checking in uncommited session.
0

In situations like this, we use the convention of an 'insertOrUpdate()' method with the following general flow. The transaction is committed by the caller of the 'insertOrUpdate()' method upon return:

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;
    }
}

Comments

0

Allocate input data to threads according to city name.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.