-->
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.  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: How to retry saveOrUpdate after PropertyValueException?
PostPosted: Mon May 16, 2005 7:09 am 
Beginner
Beginner

Joined: Mon May 16, 2005 6:06 am
Posts: 20
Hi,
what is the right way to retry saving a new/transient object where saving failed before because of a not-null constraint on one of it's properties? When I simply set the property and pass the object again to session.saveOrUpdate() I get a StaleObjectStateException probably because the object got an ID assigend on the first try even if that try failed.

Sofar I couldn't find the right information in the docs or the forum.

Any help is appreciated. Thanks in advance.

Johan

Hibernate version:
3.03

Mapping documents:
Code:
<hibernate-mapping default-access="field">
  <class name="myModel.Entity">
    <id access="field" unsaved-value="null" name="oid" type="java.lang.String" length="32">
      <generator class="uuid"/>
    </id>
    <joined-subclass name="myModel.businessObjects.Attribute" table="pm_attribute">
      <key column="oid"/>
      <property name="name" access="field" not-null="true"/>
    </joined-subclass>
  </class>
</hibernate-mapping>

Code between sessionFactory.openSession() and session.close():
Code for HibernateUtil: http://www.koders.com/java/fidC083A93BA ... C9005.aspx
Code:
public class MyHibernateDAO implements MyDAO
{
   public void delete(Entity e)
   {
      HibernateUtil.getSession().delete(e);
   }

   public List getAll(Class< ? extends Entity> clazz)
   {
      return HibernateUtil.getSession().createCriteria(clazz).list();
   }

   public List get(Class< ? extends Entity> clazz, Criterion criterion)
   {
      return HibernateUtil.getSession().createCriteria(clazz).add(criterion).list();
   }

   public Entity get(Class< ? extends Entity> clazz, String oid)
   {
      return (Entity) HibernateUtil.getSession().get(clazz, oid);
   }

   public void save(Entity e)
   {
      HibernateUtil.getSession().saveOrUpdate(e);
   }
}

Code:
public abstract class Entity
{
   private String oid = null;

   public final String getEntityOid()
   {
      return oid;
   }

   public String toString()
   {
      return getClass().getName() + "#" + oid;
   }
}

Code:
public class Attribute extends Entity
{
   private String name;

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}

Code:
public class ProductManagementTest extends TestCase
{
   public void test()
   {
      try
      {
         MyDAO myDAO = new MyHibernateDAO();
         Attribute a = new Attribute();
         try
         {
            HibernateUtil.beginTransaction();
            myDAO.save(a);
            HibernateUtil.commitTransaction();
            fail("myDAO.save() should have failed since name property of Attribute was not set");
         }
         catch (org.hibernate.PropertyValueException e)
         {
            e.printStackTrace();
            HibernateUtil.rollbackTransaction();
         }

         // now set the name property to a non-null value and try saving again
         try
         {
            HibernateUtil.beginTransaction();
            a.setName("TEST");
            myDAO.save(a);
            HibernateUtil.commitTransaction();
         }
         catch (RuntimeException e)
         {
            HibernateUtil.rollbackTransaction();
            e.printStackTrace();
            fail("myDAO.save() unexpectedly failed ");
         }
      }
      finally
      {
         HibernateUtil.closeSession();
      }
   }
}

Full stack trace of any exception that occurs:

The expected PropertyValueException on the first try to save the object
org.hibernate.PropertyValueException: not-null property references a null or transient value: myModel.businessObjects.Attribute.name
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:235)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:159)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:464)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:459)
at myModel.dao.hibernate.MyHibernateDAO.save(MyHibernateDAO.java:37)
at myModel.test.AttributeTest.test(AttributeTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)


The unexpected StaleObjectStateException on the second try to save the object
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [myModel.businessObjects.Attribute#8911707e03e51e7b0103e51e820e0001]
at org.hibernate.persister.entity.BasicEntityPersister.check(BasicEntityPersister.java:1431)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:1976)
at org.hibernate.persister.entity.BasicEntityPersister.updateOrInsert(BasicEntityPersister.java:1899)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:2139)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:75)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:137)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:726)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:320)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at myModel.dao.hibernate.HibernateUtil.commitTransaction(HibernateUtil.java:105)
at myModel.test.AttributeTest.test(AttributeTest.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
myModel.dao.hibernate.InfrastructureException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [myModel.businessObjects.Attribute#8911707e03e51e7b0103e51e820e0001]
at myModel.dao.hibernate.HibernateUtil.commitTransaction(HibernateUtil.java:112)
at myModel.test.AttributeTest.test(AttributeTest.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [myModel.businessObjects.Attribute#8911707e03e51e7b0103e51e820e0001]
at org.hibernate.persister.entity.BasicEntityPersister.check(BasicEntityPersister.java:1431)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:1976)
at org.hibernate.persister.entity.BasicEntityPersister.updateOrInsert(BasicEntityPersister.java:1899)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:2139)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:75)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:137)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:726)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:320)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at myModel.dao.hibernate.HibernateUtil.commitTransaction(HibernateUtil.java:105)
... 18 more


Name and version of the database you are using:
MySQL 4.1.7
The generated SQL (show_sql=true):
Code:
Hibernate: update pm_attribute set name=? where oid=?

Debug level Hibernate log excerpt:
16.05.2005 13:04:40 org.hibernate.cfg.Environment <clinit>
INFO: Hibernate 3.0.3
16.05.2005 13:04:40 org.hibernate.cfg.Environment <clinit>
INFO: hibernate.properties not found
16.05.2005 13:04:40 org.hibernate.cfg.Environment <clinit>
INFO: using CGLIB reflection optimizer
16.05.2005 13:04:40 org.hibernate.cfg.Environment <clinit>
INFO: using JDK 1.4 java.sql.Timestamp handling
16.05.2005 13:04:40 org.hibernate.cfg.Configuration configure
INFO: configuring from resource: /hibernate.cfg.xml
16.05.2005 13:04:40 org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: Configuration resource: /hibernate.cfg.xml
16.05.2005 13:04:41 org.hibernate.cfg.Configuration addResource
INFO: Mapping resource: myModel/Entity.hbm.xml
16.05.2005 13:04:41 org.hibernate.cfg.HbmBinder bindRootPersistentClassCommonValues
INFO: Mapping class: myModel.Entity -> Entity
16.05.2005 13:04:41 org.hibernate.cfg.HbmBinder bindJoinedSubclass
INFO: Mapping joined-subclass: myModel.businessObjects.Attribute -> pm_attribute
16.05.2005 13:04:41 org.hibernate.cfg.Configuration doConfigure
INFO: Configured SessionFactory: null
16.05.2005 13:04:41 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
16.05.2005 13:04:41 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
16.05.2005 13:04:41 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
16.05.2005 13:04:41 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
16.05.2005 13:04:42 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: Using Hibernate built-in connection pool (not for production use!)
16.05.2005 13:04:42 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: Hibernate connection pool size: 20
16.05.2005 13:04:42 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: autocommit mode: false
16.05.2005 13:04:42 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost/mymodel?useUnicode=true&characterEncoding=8859_1&autoReconnect=true
16.05.2005 13:04:42 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: connection properties: {user=root, password=geheim}
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: RDBMS: MySQL, version: 4.1.7-nt
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-3.1.8 ( $Date: 2005/04/14 20:36:13 $, $Revision: 1.27.4.64 $ )
16.05.2005 13:04:42 org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
16.05.2005 13:04:42 org.hibernate.transaction.TransactionFactoryFactory buildTransactionFactory
INFO: Using default transaction strategy (direct JDBC transactions)
16.05.2005 13:04:42 org.hibernate.transaction.TransactionManagerLookupFactory getTransactionManagerLookup
INFO: No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Automatic flush during beforeCompletion(): disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Automatic session close at end of transaction: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC batch size: 15
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC batch updates for versioned data: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Scrollable result sets: enabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC3 getGeneratedKeys(): enabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Connection release mode: null
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Maximum outer join fetch depth: 2
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Default batch fetch size: 1
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Generate SQL with comments: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Order SQL updates by primary key: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory createQueryTranslatorFactory
INFO: Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
16.05.2005 13:04:42 org.hibernate.hql.ast.ASTQueryTranslatorFactory <init>
INFO: Using ASTQueryTranslatorFactory
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Query language substitutions: {true=1, false=0}
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Second-level cache: enabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Query cache: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory createCacheProvider
INFO: Cache provider: org.hibernate.cache.EhCacheProvider
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Optimize cache for minimal puts: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Structured second-level cache entries: enabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Echoing all SQL to stdout
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Statistics: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Deleted entity synthetic identifier rollback: disabled
16.05.2005 13:04:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Default entity-mode: pojo
16.05.2005 13:04:42 org.hibernate.impl.SessionFactoryImpl <init>
INFO: building session factory
16.05.2005 13:04:42 net.sf.ehcache.config.Configurator configure
WARNUNG: No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/D:/M$/eclipse-workspace/hibernateTest/lib/hibernate/ehcache-1.1.jar!/ehcache-failsafe.xml
16.05.2005 13:04:42 org.hibernate.impl.SessionFactoryObjectFactory addInstance
INFO: Not binding factory to JNDI, no JNDI name configured
16.05.2005 13:04:42 org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
16.05.2005 13:04:42 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
16.05.2005 13:04:42 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
16.05.2005 13:04:42 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
16.05.2005 13:04:42 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
16.05.2005 13:04:42 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
16.05.2005 13:04:43 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
16.05.2005 13:04:43 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
16.05.2005 13:04:43 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
16.05.2005 13:04:43 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: Running hbm2ddl schema export
16.05.2005 13:04:43 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: exporting generated schema to database
16.05.2005 13:04:43 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: Using Hibernate built-in connection pool (not for production use!)
16.05.2005 13:04:43 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: Hibernate connection pool size: 20
16.05.2005 13:04:43 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: autocommit mode: false
16.05.2005 13:04:43 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost/mymodel?useUnicode=true&characterEncoding=8859_1&autoReconnect=true
16.05.2005 13:04:43 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: connection properties: {user=root, password=geheim}
16.05.2005 13:04:43 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: schema export complete
16.05.2005 13:04:43 org.hibernate.connection.DriverManagerConnectionProvider close
INFO: cleaning up connection pool: jdbc:mysql://localhost/mymodel?useUnicode=true&characterEncoding=8859_1&autoReconnect=true
16.05.2005 13:04:43 org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
16.05.2005 13:04:44 org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
16.05.2005 13:04:44 org.hibernate.impl.SessionFactoryImpl checkNamedQueries
INFO: Checking 0 named queries
org.hibernate.PropertyValueException: not-null property references a null or transient value: myModel.businessObjects.Attribute.name
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:235)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:159)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:464)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:459)
at myModel.dao.hibernate.MyHibernateDAO.save(MyHibernateDAO.java:37)
at myModel.test.AttributeTest.test(AttributeTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
Hibernate: update pm_attribute set name=? where oid=?
16.05.2005 13:04:44 org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SCHWERWIEGEND: Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [myModel.businessObjects.Attribute#8911707e03e52d520103e52d591d0001]
at org.hibernate.persister.entity.BasicEntityPersister.check(BasicEntityPersister.java:1431)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:1976)
at org.hibernate.persister.entity.BasicEntityPersister.updateOrInsert(BasicEntityPersister.java:1899)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:2139)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:75)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:137)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:726)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:320)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at myModel.dao.hibernate.HibernateUtil.commitTransaction(HibernateUtil.java:105)
at myModel.test.AttributeTest.test(AttributeTest.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
myModel.dao.hibernate.InfrastructureException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [myModel.businessObjects.Attribute#8911707e03e52d520103e52d591d0001]
at myModel.dao.hibernate.HibernateUtil.commitTransaction(HibernateUtil.java:112)
at myModel.test.AttributeTest.test(AttributeTest.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [myModel.businessObjects.Attribute#8911707e03e52d520103e52d591d0001]
at org.hibernate.persister.entity.BasicEntityPersister.check(BasicEntityPersister.java:1431)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:1976)
at org.hibernate.persister.entity.BasicEntityPersister.updateOrInsert(BasicEntityPersister.java:1899)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:2139)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:75)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:137)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:726)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:320)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at myModel.dao.hibernate.HibernateUtil.commitTransaction(HibernateUtil.java:105)
... 18 more


Top
 Profile  
 
 Post subject: Found a JIRA Entry
PostPosted: Mon May 16, 2005 9:51 am 
Beginner
Beginner

Joined: Mon May 16, 2005 6:06 am
Posts: 20
I just found this JIRA Entry: http://opensource.atlassian.com/projects/hibernate/browse/HB-1014

As far as I understand Christian Bauer says that Hibernate3 can automatically remove the IDs assigned to new objects on a rollback. In my case it didn't and I think this is the reason for the StaleObjectStateException. Do I need to use another method than saveOrUpdate to persist my objects or do I set any special hibernate settings?[/url]


Top
 Profile  
 
 Post subject: Seems to be a common problem
PostPosted: Mon May 16, 2005 4:17 pm 
Beginner
Beginner

Joined: Mon May 16, 2005 6:06 am
Posts: 20
I continued searching for a solution and I realize that I'm not the only one facing this issue but so far none of the related forum entries has been answered sufficiently:

http://forum.hibernate.org/viewtopic.php?t=941985
http://forum.hibernate.org/viewtopic.php?t=941924
http://forum.hibernate.org/viewtopic.php?t=940028
http://forum.hibernate.org/viewtopic.php?t=931005
http://forum.hibernate.org/viewtopic.php?t=927514

Is being able to retry a save operation of a new or modified object asked to much from a persistence framework?

Regarding already persisted object for example: For a simple mapping it might be ok to reload a single object from the database and apply the modifications again and then retry saving. But if you need to persist a complex object graph and calling saveOrUpdate invalidates all referenced objects its getting a messy job to reload and reapply all the changes again esp. when the modifications where made in different layers of the application.

So what is the technical problem for hibernate to simply allow a retry of saveOrUpdate operations?


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 17, 2005 2:09 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
AFAIK exceptions thrown by hibernate are not recovarable. You have to rollback and close your session and start again.
At least that was true for H2, I'm not 100% sure for H3.

HTH
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Sat May 21, 2005 10:58 am 
Beginner
Beginner

Joined: Mon May 16, 2005 6:06 am
Posts: 20
Closing and restartin the session is not the problem. The problem is that a new session doesn't accept my objects anymore even if I corrected the reason why persisting failed before. I can't believe that there shall be no real solution for this.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 22, 2005 9:40 am 
Newbie

Joined: Sat Jan 29, 2005 7:09 am
Posts: 11
Hi - I originally posted this one: http://forum.hibernate.org/viewtopic.php?t=941924.

I settled on a strategy for doing what you want to do. I use an Interceptor on the session that looks like this:


public boolean onFlushDirty(Object entity, Serializable id, Object[] states, Object[] previousStates, String[] properties, Type[] types) throws CallbackException
{
collector.updating((IPersistable)entity);
return false;
}

public boolean onSave(Object entity, Serializable arg1, Object[] arg2, String[] arg3, Type[] arg4) throws CallbackException
{
collector.inserting((IPersistable)entity);
return false;
}
public void onDelete(Object arg0, Serializable arg1, Object[] arg2, String[] arg3, Type[] arg4) throws CallbackException
{
collector.deleting((IPersistable)arg0);
}


Then, if any exceptions occurred, reset the object graph by setting all the inserted identifiers back to null


List inserts = collector.getInserts();
for (int i=0;i<inserts.size();i++)
{
IPersistable p = (IPersistable)inserts.get(i);
try
{
ClassMetadata meta =
sessionFactory.getClassMetadata(p.getClass());
meta.setIdentifier(p,null,EntityMode.POJO);
}
catch (HibernateException e)
{}
}


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 29, 2005 6:44 am 
Beginner
Beginner

Joined: Mon May 16, 2005 6:06 am
Posts: 20
Hi satch,

thanks a lot for your code example. I'll give it a try.

Do you think its possible to bind a collector instance to a specific transaction? Your code looks like if I would commit 2 transactions concurrently and one fails the collector rolls back the ids for the objects of both transactions.

I still find the stand point/adivces of the hibernate developers ridiculous. How can it be the app developers responsible to "rollback to an acceptable domain object state" without knowing how the persistence layer screws up the objects. To me this looks like there is a deep problem in the Hibernate architecture.

Cheers,
Johan


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 29, 2005 1:29 pm 
Newbie

Joined: Sat Jan 29, 2005 7:09 am
Posts: 11
You can create a brand new Interceptor for each new Session via SessionFactory.openSession(new MyInterceptor()).

Your code should enforce that only one Thread accesses a Session at any given time, because Sessions are not thread-safe, and a Transaction can only be associated with a single Session.

So the above code will work just fine for multiple concurrent Transactions as long as each Transaction is taking place on a different Session and on a separate Thread. The majority of people use the ThreadLocal pattern to guarantee this (though I use other ways).

I do agree with you to some extent about Hibernate - I would have thought that the id setting would automatically be undone by the Hibernate core, and there are certain other aspects of Hibernate that do not work quite as I'd hoped, but in all in all it is a damn good piece of software for free.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 13, 2005 7:22 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
Apparently Hibernate 3 contains some fixes for this already (see this JIRA entry).

This JIRA entry mentions a related bug which has only been fixed in Hibernate 3.

I've posted a lot of links in a lot of different threads back to this one -- anyone joining in please share your recent experience here!

Here is our version of this problem:

We let the user edit several separate objects, called Sections. Sections are immutable objects held in Slots. We have version-based conflict detection on Slots (via version field). A user makes an edit by changing the Section field of a Slot.

We would ideally like for the user to be able to save any or all of these sections at any time. One key requirement is that the user NOT have to save ALL the sections. Another requirement is that if another user updated a Slot, then the saving user gets asked whether to overwrite their changes or discard their own.

We are currently using a single long session for the user's whole editing session, with transactions whenever we are saving or opening new sections.

Overall, then, we would really like to not have to throw away the complete state of our session just because we got a stale exception when changing one particular slot. There is other, unsaved state in our session that we don't want to (or need to) discard.

So, basically, we want to recover from StaleObjectStateException! Or, at least, avoid it!

Here's our plan:

Code:
For each section the user wants to save,
- Get the (detached) slot for that section
- Save its version number
- Reattach the session, and call session.refresh(slot, LockMode.UPGRADE)
- If the slot now has an updated version number, ask the user whether to overwrite the changes or not
- If the user wants to, then update the slot
- If the user doesn't want to, then refresh the UI with the new contents of the slot


This is an unconventional and apparently non-recommended use of session.refresh, but it should work :-) We may also make use of some of the interceptor pattern above, which looks like it could be all kinds of useful.

In general, if you have full control over your application, I can't see why it should be necessary to throw your session away. It might take some careful pessimism, but in general it seems like StaleObjectStateExceptions, in general, *can* be managed within a long-running detached Session. (If, that is, you think carefully about your domain model and where it gets updated and version-checked.)

Let's see where this thread goes from here :-)
Cheers!
Rob


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 13, 2005 8:30 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
Oops, garbled my first JIRA link above. I meant the link to HB-1014 mentioned earlier in this thread. Sorry!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 14, 2005 1:28 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
Whoop, it's a one-person party here :-) Well, we won't be doing the above, since obviously we mustn't hold a database lock during a dialog with the user. But certain variations of that look hopeful. Anyway, hope to hear from others sooner or later!
Cheers,
Rob


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 17, 2005 6:47 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
OK, so what we're doing now is:

Code:
1) Collect the set of changes to be saved.
2) Do the following on all the objects that should be updated:
    long oldVersion = objectToUpdate.getVersion();
    session.refresh(objectToUpdate, LockMode.UPGRADE);
    long newVersion = objectToUpdate.getVersion();
    if (oldVersion != newVersion) {
        conflictSet.add(objectToUpdate);
    }
3) If conflictSet is not empty, then:
    - flush and commit WITHOUT changing any of the objectsToUpdate. 
    - Ask the user what to do (overwrite other user's changes? or discard user's own changes?). 
    - Open another transaction.
    - Go back to step 1) to try locking everything again.


Since we are refreshing with LockMode.UPGRADE, we know that no one else can sneak in and update these objects again after we've verified that they haven't changed.

We make sure to do the session.refresh calls in order of object ID, so we have a consistent lock ordering in the database.

In a certain sense this is "a lot of optimism with a little pessimism" -- we use the Hibernate version numbers to let us avoid holding DB locks during user think time, but we use Hibernate pessimistic locking to apply a set of object updates in a consistent manner (without risking intervening StaleObjectStateExceptions).

This seems to rather neatly avoid the need to EVER catch or recover from StaleObjectExceptions! I'm rather surprised that this pattern isn't standard Hibernate practice. I'm uneasily waiting for Christian or Gavin to shoot a huge hole in it, but it seems to work great for us :-D

Cheers!
Rob


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 17, 2005 7:45 pm 
Beginner
Beginner

Joined: Wed Dec 31, 2003 1:40 pm
Posts: 25
Hey Rob, thanks for the link to your thread. This is an important issue that I wasn't quite aware of yet. I have created an - as yet quite disorderly - article on the Wiki to summarize the issues and approaches with rich clients: http://hibernate.org/333.html. Your findings here definitely need to go into this article.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 15, 2006 7:02 am 
Newbie

Joined: Wed Sep 21, 2005 7:57 am
Posts: 7
Location: Lausanne, Switzerland
Hello,

Here http://opensource2.atlassian.com/projec ... se/HB-1014 Christian says a fix has been added in hibernate 3.

I'm running hib3 and still has this problem, what should I do or configure to use this fix ?

Anyone ?

JP


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 22, 2006 11:07 am 
Beginner
Beginner

Joined: Thu Nov 24, 2005 2:58 pm
Posts: 21
JIRA has it marked as closed/rejected and as of 3.1.3 I still see the bug/feature/design flaw/reasonable compromise (depending on your POV). If this were a democracy I'd vote to have H3 null the IDs and leave the other pojo fields alone.

so is this meant to be fixed or not guys?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next

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.