6 Replies Latest reply on Jan 18, 2010 3:47 PM by adamw

    Envers auditing with Hibernate versioning

    skomarla

      Has anyone seen odd behavior with

       

      using envers and the session cache? I know Adam will ask me for a unit test, but this is a hard one


      Object A is versioned (I mean hibernate optimistic locking versioning) and envers Audited

       

      User 1 edits instance a of A via a webpage, and changes a primitive value and saves it
      instance a is saved to db using hibernate generic dao. Data in DB is updated (row_version goes from 1 -> 2)

       

      User 2 in a different browser session also edits instance a (retrieves version 2) and saves it
      instance a is saved to db using hibernate generic dao. Data in DB is updated (row_version goes from 2 -> 3)

       


      User 1 then retrieves the object and makes another change. The problem occurs here. When the user submits the page, and a dao is used to load the object via the pk, hibernate retrieves version 2 of the object (not version 3).  A subsequent update and save yields a "optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):"

       

      Has anyone seen this? If I take out the envers revision listener, this does not happen.  I have tried it many many times. Now with the envers listener in play, if I explicitly retrieve the object and force an evict from the session, and retrieve it again, it loads version 3

       


      This is running in JBoss with JTA and Spring 2.5.6 and envers 1.2.2.GA, but I have seen this with envers 1.2.1.GA as well.

       

      some code snippets.

       

      SpringMVC controller method:

       

        @RequestMapping("/networkNodes/viewRoutingInfo.do")
        public void viewRoutingObjectVersion(ServletRequest req, ServletResponse resp, @RequestParam("routingId") Integer routingId) throws IOException {
          
          Routing r = routingService.findRoutingDetails(routingId);
          try {
            resp.getOutputStream().print(r.getObjectVersion() + "<br>");
      
            // modified
            routingService.testRoutingUpdate(routingId);
            r = routingService.findRoutingDetails(routingId);
            resp.getOutputStream().print("after first mod " + r.getObjectVersion() + "<br>");
            
            routingService.testRoutingUpdate(routingId);
            r = routingService.findRoutingDetails(routingId);
            resp.getOutputStream().print("after second mod " + r.getObjectVersion() + "<br>");
          } catch (Exception e) {
            resp.getOutputStream().print(e.getMessage());
          }
        }
      

       

      routingService is a Spring bean that is Transactional via @Transactional annotation.


        public void testRoutingUpdate(int routingId) {
          
          Routing r = routingDao.get(routingId);
          r.setDataQuality(r.getDataQuality()+1);
      
          routingDao.update(r);
        }
      

       

      Some misc code though I don't believe them to be relevant:

       

      RoutingDao is

      public interface RoutingDao extends GenericDao<Routing, Integer> {
      

       

       

      GenericDao is

      public interface GenericDao<T, PK extends Serializable> {
      

       

      GenericDaoImpl is

      public class GenericDaoImpl<T, PK extends Serializable> extends
      
          HibernateDaoSupport implements GenericDao<T, PK>, FinderExecutor<T> {
      

       

       

      Some output (the URL i'm hitting with browser)
      http://skomarla:8080/ifn-springmvc-web/networkNodes/viewRoutingInfo.do?routingId=8
      User 1 req 1:
      156
      after first mod 157
      after second mod 158

       

      User 2 req 1:
      158
      after first mod 159
      after second mod 160

       

      User 1 req 2:
      158
      Object of class [com.sterling.ifn.model.Routing] with identifier [8]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.sterling.ifn.model.Routing#8]

       

      Notice how User 1's second req retrieved version 156