I have the following code :
Code:
Transaction transaction = null;
try {
SupplierDao supplierDao = SuppliersEMDaoFactory.getInstance().getSupplierDao();
Session hibernateSession = ServiceLocator.getCurrentSession();
transaction = hibernateSession.beginTransaction();
Supplier supplier = new Supplier();
supplierDao.generateKey(supplier);
supplier.setName("Name1");
hibernateSession.saveOrUpdate(supplier);
supplier.setName("Name2"); // bad code
hibernateSession.flush();
transaction.commit();
}
catch (Exception e) {
e.printStackTrace();
transaction.rollback();
}
When I execute it, the following exception is thrown by the flush() call :
Code:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [net.cpaerp.suppliers.application.business.entity.Supplier#a37a9e6fffffff80006060325ce866f9]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1714)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2357)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2257)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2557)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at net.cpaerp.suppliers.application.presentation.TestExecute.execute(TestExecute.java:74)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:421)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:226)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1164)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:397)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:697)
...
(the code is in the execute method of the TestExecute struts action class)
If i remove the line
Code:
supplier.setName("Name2"); // bad code
I have no error.
I'm using the last release of Hibernate 3.2.1 GA
This are my config files :
Code:
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
<property name="connection.datasource">java:/DefaultDS</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="current_session_context_class">managed</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
<mapping resource="net/cpaerp/suppliers/application/business/entity/Contact.hbm.xml"/>
<mapping resource="net/cpaerp/suppliers/application/business/entity/Supplier.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Supplier.hbm.xml :
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping >
<class
name="net.cpaerp.suppliers.application.business.entity.Supplier"
table="Supplier"
optimistic-lock="version"
mutable="true"
>
<id
name="id"
column="uniqueId"
type="string">
<generator class="assigned"/>
</id>
<timestamp
name="timestamp"
column="timestamp_column"
/>
<property name="name" type="string">
<column name="name"/>
</property>
<property name="telephone" type="string">
<column name="telephone"/>
</property>
<bag
name="contact"
inverse="true"
cascade="save-update,merge"
>
<key>
<column name="SupplierUniqueId"/>
</key>
<one-to-many
class="net.cpaerp.suppliers.application.business.entity.Contact"
/>
</bag>
</class>
<query name="Supplier_findAll">
<![CDATA[
select new list(supplier)
FROM Supplier AS supplier
]]>
</query>
<query name="Supplier_findByContact">
<![CDATA[
select new list(supplier)
FROM Supplier AS supplier
LEFT JOIN supplier.contact AS contact
WHERE contact.id = :contactId
]]>
</query>
<query name="Supplier_findByName">
<![CDATA[
select new list(supplier)
FROM Supplier AS supplier
WHERE supplier.name LIKE :name
]]>
</query>
</hibernate-mapping>
Do anybody have an idea??
Why can't we modify a new object after calling the saveOrUpdate (or just save) method on the hibernate session? Is this normal? Is it some kind of locking issue?
I use the timestamp versionning feature. After calling the saveOrUpdate method with my object, the value of the timestamp column is initialized to now.
Two lines are logged in the org.hibernate.SQL logger :
Code:
insert into Supplier (timestamp_column, name, telephone, uniqueId) values (?, ?, ?, ?)
update Supplier set timestamp_column=?, name=?, telephone=? where uniqueId=? and timestamp_column=?
Obviously, the insertion is done in two database access. One for inserting, and one for some update. I set autocommit to true to see what was inserted on the insert call, and the following fields were filled :
- the id column with the key generated by my dao
- the timestamp column
- the name column with the value "name1"
And the second update update nothing, the exception is thrown and the transaction rollbacked.
I'm confuse... how can I cancel the first insert and replace the update by an insert with the same values?
Emmanuel