-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: unexpected update during simple select
PostPosted: Tue May 16, 2006 1:39 pm 
Newbie

Joined: Wed Nov 02, 2005 1:17 pm
Posts: 13
I'm getting unexpected updates that occur whenever I end of flush a transaction. The updates occur on classes unrelated to the query. The classes that are getting updated all have a userDefined type (called ACLUserType). If I remove any references to the userType the unexpected updates go away and everything works as expected. This is a problem because the updates are locking out other users from accessing those tables.

Hibernate version: 3.0.5

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

<hibernate-mapping>
  <class name="gov.llnl.e3.model.E3User" table="E3_USER">
    <id name="id" column="ID" type="long">
      <generator class="native"/>
    </id>
       
     <property name="userId" unique="true" not-null="true" column="USER_ID" />
     <property name="lastName" column="LAST_NAME" />
     <property name="firstName" column="FIRST_NAME" />
     <property name="emailAddress" column="EMAIL_ADDRESS" />
     <property name="phoneNumber" column="PHONE_NUMBER" />
    
     <many-to-one name="defaultGroup" column="DEFAULT_GROUP"  not-null="true"/>
    
     <property name="defaultACL" type="gov.llnl.e3.model.ACLUserType" not-null="true">
         <column name="DEFAULT_ACL" sql-type="acl"/>
     </property>

     <set name="groups" table="USER_GROUP_SET" lazy="true" cascade="all">
        <key column="USER_ID"/>
        <many-to-many class="gov.llnl.e3.model.E3Group" column="GROUP_ID"/>
     </set>
    
     <set name="views" table="USER_VIEW_SET" lazy="true" cascade="all">
        <key column="USER_ID"/>
        <many-to-many class="gov.llnl.e3.model.E3View" column="VIEW_ID"/>
     </set>
    
  </class>
</hibernate-mapping>



Code between sessionFactory.openSession() and session.close():
I'm following session-per-request model. Here is how I start and end transactions:
Code:
   public void startTransaction() {
      start = System.currentTimeMillis();

      if (session == null) {
         throw new E3InitializationException(
               "Attempt to start a transaction without initializing the session first!");
      }

      try {
         transaction = session.beginTransaction();
         logger.info("transaction started id: " + transaction.hashCode());

      } catch (HibernateException e) {
         logger.error("Exception while starting transaction: ", e);
         throw (E3DatabaseAccessException) new E3DatabaseAccessException().initCause(e);
      }
   }

   public void endTransaction(boolean trnxError) {

      // make sure we're initialized...
      if (session == null) {
         throw new E3InitializationException("Attempt to end a transaction without initializing the session first!");
      }
      // ... and that we're in a transaction.
      if (transaction == null) {
         throw new E3InitializationException("Attempt to end a transaction before starting a transaction");
      }

      try {
         if (trnxError) {
            transaction.rollback();
         } else {
            transaction.commit();
            session.flush();
            logger.info("flushing transaction id: " + transaction.hashCode());
         }
      } catch (HibernateException e) {
         logger.error("Exception while ending transaction: ", e);
         // if commit failed, then try to rollback transaction
         try {
            transaction.rollback();
         } catch (HibernateException e1) {
            logger.error("Exception while trying to rollback transaction: ", e1);
            throw new E3DatabaseAccessException("Error while attempting to rollback transaction.", e1);
         }

         throw new E3DatabaseAccessException("Error while attempting to end transaction with Hibernate.", e);
      } finally {
         // mark that we're not in a transaction anymore
         if (transaction.isActive())
            logger.info("!!!! Transaction still active");

         transaction = null;
         stop = System.currentTimeMillis() - start;
         logger.info("***** End Transaction.  Time: " + stop + "\n");
      }
   }



Name and version of the database you are using:
E3DB - Oracle 10g

The generated SQL (show_sql=true):
Here's the logging output and generated SQL that is produced from a simple query of the E3User table (notice the UPDATEs to E3User). The first update occurs as a result of transaction.commit(); in the endTransaction method above. The second update occurs as a result of the next statement (session.flush()):
Code:
transaction started id: 27104945
4172 [AWT-EventQueue-0] INFO  (E3Manager.java:269) - transaction started id: 27104945
Hibernate: select e3user0_.ID as ID, e3user0_.USER_ID as USER2_17_, e3user0_.LAST_NAME as LAST3_17_, e3user0_.FIRST_NAME as FIRST4_17_, e3user0_.EMAIL_ADDRESS as EMAIL5_17_, e3user0_.PHONE_NUMBER as PHONE6_17_, e3user0_.DEFAULT_GROUP as DEFAULT7_17_, e3user0_.DEFAULT_ACL as DEFAULT8_17_ from E3_USER e3user0_ where e3user0_.USER_ID=?
[color=red]]Hibernate: update E3_USER set USER_ID=?, LAST_NAME=?, FIRST_NAME=?, EMAIL_ADDRESS=?, PHONE_NUMBER=?, DEFAULT_GROUP=?, DEFAULT_ACL=? where ID=?
Hibernate: update E3_USER set USER_ID=?, LAST_NAME=?, FIRST_NAME=?, EMAIL_ADDRESS=?, PHONE_NUMBER=?, DEFAULT_GROUP=?, DEFAULT_ACL=? where ID=?[/color]
flushing transaction id: 27104945
4781 [AWT-EventQueue-0] INFO  (E3Manager.java:311) - flushing transaction id: 27104945
***** End Transaction.  Time: 609


Here's the logging output and SQL from a second query to an unrelated table - BENUm (notice the same UPDATEs to E3User)::
Code:
transaction started id: 18690717
4828 [main] INFO  (E3Manager.java:269) - transaction started id: 18690717
Hibernate: select benum0_.ID as ID, benum0_.BE_PREFIX as BE2_8_, benum0_.BE_SUFFIX as BE3_8_, benum0_.TARGET_NAME as TARGET4_8_, benum0_.CENTROID as CENTROID8_, benum0_.DEFAULT_IMAGE_ID as DEFAULT6_8_, benum0_.COUNTRY_CODE_ID as COUNTRY7_8_ from BE_NUM benum0_ inner join ABSTRACT_E3_ELEMENT benum0_1_ on benum0_.ID=benum0_1_.ID
Hibernate: update E3_USER set USER_ID=?, LAST_NAME=?, FIRST_NAME=?, EMAIL_ADDRESS=?, PHONE_NUMBER=?, DEFAULT_GROUP=?, DEFAULT_ACL=? where ID=?
Hibernate: update E3_USER set USER_ID=?, LAST_NAME=?, FIRST_NAME=?, EMAIL_ADDRESS=?, PHONE_NUMBER=?, DEFAULT_GROUP=?, DEFAULT_ACL=? where ID=?

flushing transaction id: 18690717
5063 [main] INFO  (E3Manager.java:311) - flushing transaction id: 18690717
***** End Transaction.  Time: 235


When I remove the ACLUserType from the E3User table the above updates don't occur.

Here's the definition of my ACLUserType:

Code:
package gov.llnl.e3.model;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import oracle.jdbc.driver.OracleConnection;
import oracle.spatial.geometry.JGeometry;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;

import org.hibernate.HibernateException;
import org.hibernate.type.LongType;
import org.hibernate.usertype.UserType;

public class ACLUserType implements UserType {

    private static final int[] SQL_TYPES = {Types.STRUCT};
   
    private static final String DB_OBJECT_TYPE = "E3.ACL";
   
    public int[] sqlTypes() {
        return SQL_TYPES;
    }   


    public Class returnedClass() {
        return STRUCT.class;
    }
   
    public int hashCode(Object o) throws HibernateException {
        return ((STRUCT)o).hashCode();
    }

    public boolean equals(Object o1, Object o2) throws HibernateException {
      if (o1 == o2) {
         return true;
      }
      if (o1 == null || o2 == null) {
         return false;
      }
      return false;
   }

    public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
         throws HibernateException, SQLException {
      assert names.length == 1;
      final STRUCT struct = (STRUCT) resultSet.getObject(names[0]);
      if (resultSet.wasNull()) {
         return null;
      }
      final ACL acl = new ACL();
      acl.setUserOwnerId(new Long(((BigDecimal) struct.getAttributes()[0]).longValue()));
      acl.setGroupOwnerId(new Long(((BigDecimal) struct.getAttributes()[1]).longValue()));

      if (struct.getAttributes()[2] != null)
         acl.setOwnerRead(new Integer(((BigDecimal) struct.getAttributes()[2]).intValue()));
      if (struct.getAttributes()[3] != null)
         acl.setGroupRead(new Integer(((BigDecimal) struct.getAttributes()[3]).intValue()));
      if (struct.getAttributes()[4] != null)
         acl.setWorldRead(new Integer(((BigDecimal) struct.getAttributes()[4]).intValue()));
      if (struct.getAttributes()[5] != null)
         acl.setOwnerWrite(new Integer(((BigDecimal) struct.getAttributes()[5]).intValue()));
      if (struct.getAttributes()[6] != null)
         acl.setGroupWrite(new Integer(((BigDecimal) struct.getAttributes()[6]).intValue()));
      if (struct.getAttributes()[7] != null)
         acl.setWorldWrite(new Integer(((BigDecimal) struct.getAttributes()[7]).intValue()));
      if (struct.getAttributes()[8] != null)
         acl.setOwnerDelete(new Integer(((BigDecimal) struct.getAttributes()[8]).intValue()));
      if (struct.getAttributes()[9] != null)
         acl.setGroupDelete(new Integer(((BigDecimal) struct.getAttributes()[9]).intValue()));
      if (struct.getAttributes()[10] != null)
         acl.setWorldDelete(new Integer(((BigDecimal) struct.getAttributes()[10]).intValue()));

      return acl;
   }

    public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException {
      if (value == null) {
         preparedStatement.setNull(index, Types.STRUCT, DB_OBJECT_TYPE);
      } else {
         final ACL acl = (ACL) value;
         final Object[] values = new Object[] {
               acl.getUserOwnerId(),
               acl.getGroupOwnerId(),
               acl.getOwnerRead(),
               acl.getGroupRead(),
               acl.getWorldRead(),
               acl.getOwnerWrite(),
               acl.getGroupWrite(),
               acl.getWorldWrite(),
               acl.getOwnerDelete(),
               acl.getGroupDelete(),
               acl.getWorldDelete() };
   
           OracleConnection oc = (OracleConnection)preparedStatement.getConnection();
         final STRUCT struct = new STRUCT(StructDescriptor.createDescriptor(DB_OBJECT_TYPE, oc), oc, values);
         preparedStatement.setObject(index, struct);
      }
   }

    public Object deepCopy(Object o) throws HibernateException {
        if (o == null)
            return null;

        return ((ACL) o).clone();
    }

    public boolean isMutable() {
        return false;
    }

    public Serializable disassemble(Object o) throws HibernateException {
        return (Serializable) deepCopy(o);
    }

    public Object assemble(Serializable serializable, Object o) throws HibernateException {
        return deepCopy(serializable);
    }

    public Object replace(Object o, Object o1, Object o2) throws HibernateException {
        return (STRUCT) o;
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 1:45 pm 
Regular
Regular

Joined: Wed Aug 25, 2004 6:23 am
Posts: 91
You are using hashCode() from STRUCT, so you should use the equals method from there too - does this help?

Code:
public boolean equals(Object o1, Object o2) throws HibernateException {
      if (o1 == o2) {
         return true;
      }
      if (o1 != null) {
         return o1.equals(o2);
      }
      return false;
   }


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 2:16 pm 
Newbie

Joined: Wed Nov 02, 2005 1:17 pm
Posts: 13
Thanks for the suggestion and you were right on the "equals" however, it had no effect on the extraneous updates


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 4:00 pm 
Regular
Regular

Joined: Wed Aug 25, 2004 6:23 am
Posts: 91
It is probably something to do with that equals method - try setting a breakpoint on it to see when (and why) it returns false. Or if that fails turn up the Hibernate log to debug level and search for 'is dirty'


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 5:04 pm 
Newbie

Joined: Wed Nov 02, 2005 1:17 pm
Posts: 13
Thanks alot.. that helped.. I went back and did a more thorough test for equality and it worked.

Code:
public boolean equals(Object o1, Object o2) throws HibernateException {
        if (o1 == o2) {
           return true;
        }
        if ((o1 != null) && (o2 != null)) {
           ACL acl1 = (ACL) o1;
           ACL acl2 = (ACL) o2;
           if ((acl1.getUserOwnerId().equals(acl2.getUserOwnerId())) &&
                   (acl1.getGroupOwnerId().equals(acl2.getGroupOwnerId()))&&
                   (acl1.getOwnerRead().equals(acl2.getOwnerRead()))&&
                   (acl1.getOwnerWrite().equals(acl2.getOwnerWrite()))&&
                   (acl1.getOwnerDelete().equals(acl2.getOwnerDelete()))&&
                   (acl1.getGroupRead().equals(acl2.getGroupRead()))&&
                   (acl1.getGroupWrite().equals(acl2.getGroupWrite()))&&
                   (acl1.getGroupDelete().equals(acl2.getGroupDelete()))&&
                   (acl1.getWorldRead().equals(acl2.getWorldRead()))&&
                   (acl1.getWorldWrite().equals(acl2.getWorldWrite()))&&
                   (acl1.getWorldDelete().equals(acl2.getWorldDelete())))
              return true;
        }
        return false;
     }


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.