Hibernate session not refreshing data from DB after initial commit failure

夙愿已清 提交于 2019-12-13 19:25:42

问题


I am working on a multithreaded Java application that uses Hibernate. We are getting a org.hibernate.StaleObjectStateException because we have optimistic locking in place and a certain entity (let's call it Pojo) is updated from many application modules, which can and have collided in race conditions (I have not designed the application). The problematic code block looks something like this:

Transaction txn = null;
HibernateException ex = null

for(int retryAttempt = 0; retryAttempt < 5; retryAttempt++) {
    try {
        txn = hibnSessn.beginTransaction();

        int pojoID = pojo.getID();
        pojo = hibnSessn.get(Pojo.class, pojoID);

        pojo.setSomeVar("xyz");

        txn.commit();

        ex = null;
    } catch(HibernateException e) {
        if (txn != null)
        {
            txn.rollback();
        }

        ex = e;
        // Gonna keep retrying
        continue;
    }

    break;
}

And Pojo.hbm.xml starts something like this:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.myproject.Pojo" table="pojo">
        <id name="id" column="id" type="int">
            <generator class="identity"/>
        </id>
        <!-- this is used to enforce optimistic locking -->
        <version name="dbVersion" column="db_version"/>
        ...

The original author of this code put in the above retry loop precisely because there are other modules that also update Pojo and if the initial commit fails due to a race condition, we go into additional attempts, hoping to succeed in a clean, unconflicted transaction. I dislike this pattern but have to work with it for the time being.

I have been able to instrument the race condition by breaking at line pojo.setSomeVar("xyz");, updating the database from another thread/method, and proceeding, which fails the commit and goes into the catch, due to the optimistic locking, rolling back and going into the next iteration of the retry loop.

The problem is that, in the second iteration, the line pojo = hibnSessn.get(Pojo.class, pojoID); does not refresh pojo with the fresh data from DB but pulls the stale object from the session, defeating the purpose of the retry.

Another interesting thing is that hibnSessn.get(...) does actually go into the DB (under normal conditions) because when I change the data from another thread/method before hibnSessn.get in the first iteration before a commit failure, the object does get refreshed. It only fails to do so after a commit has failed and the transaction rolled back.

I am looking for ways to force Hibernate to go into the DB and refresh the object after an initial commit failure.

UPDATE: I tried evict/refresh in the catch to refresh the object but that also resulted in a StaleObjectStateException.

RELATED: https://stackoverflow.com/questions/19364343/staleobjectstateexception-when-evicting-refreshing-stale-object-from-hibernate-s


回答1:


You could try evicting the object from the session in the catch.

hibnSessn.evict(pojo);

The get on the retry should then get a fresh copy from the DB.

Refreshing it might also work.

hibnSessn.refresh(pojo);



回答2:


hibnSessn.flush() will remove the staleobject (every entity for that matter) from the Session. Thus retrieve from the db for e.g.

    hibnSessn.flush()
    pojo = hibnSessn.get(Pojo.class, pojoID);


来源:https://stackoverflow.com/questions/19329338/hibernate-session-not-refreshing-data-from-db-after-initial-commit-failure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!