aspose file tools*
The moose likes Object Relational Mapping and the fly likes Issue with saving pojo in a transactional wrapper Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Databases » Object Relational Mapping
Bookmark "Issue with saving pojo in a transactional wrapper" Watch "Issue with saving pojo in a transactional wrapper" New topic
Author

Issue with saving pojo in a transactional wrapper

Madhuri Ramanathan
Greenhorn

Joined: Jun 12, 2008
Posts: 3
I have a few simplistic use case that we are prototyping to get familiar with Spring and Hibernate processes for use in an enterprise application. I have been running into some hard to understand issues and was hoping to get some help from folks that have more experience in this than me.

Here is some information about my application:

I have a basic pojo with a single child object which is eagerly loaded. The repository for this pojo implements the basic CRUD apis using the spring HibernateDaoSupport and HibernateTemplate classes. Note, the repository implements create/update via a single "save" method that calls the "getHibernateTemplate().saveOrUpdate()" api.

My service/facades are wrapped in a transactionManager support (I finally got this to work). The service API for create/update has some additional logic that requires me to read back a list of pojos based on a key (the list will include the pojo that I have updated in the case of an update usecase) and after some validation checks saves the pojo. Now, this is where my problem starts.

My service API looks something as follows:

public CreatePojoResult createFreePeriod(Pojo pojoInstance)
{

int nUser;

// get list of Pojos for user
_repository.getPojosForUser(nUser);

// Run my validation checks << omitted here >>

// save my Pojo
_repository.save(pojoInstance);

// create and return the result object. << omitted here >>
}


When I call the createFreePeriod() API above from my facade for my insert use-case, everything works fine. However, when I call it for my update use-case, I get the following error.

org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [Pojo#1455148::1]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [Pojo#1455148::1]
org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:661)
org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:744)
org.springframework.orm.hibernate3.HibernateTemplate$$FastClassByCGLIB$$cf0d264a.invoke(<generated>
net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
org.springframework.orm.hibernate3.HibernateTemplate$$EnhancerByCGLIB$$8ece0e67.saveOrUpdate(<generated>
domain.core.EntityRepositoryImpl.save(EntityRepositoryImpl.java:63)

Note, I clearly do not get this issue when my facade is not wrapped within a transaction, but that is not an option for me. Note, the pojo that I hold during the update use case is detached. So, I assume my issue has to do with the fact that pojo being passed in is not managed while the getPojosForUser() operation prior to the save creates another pojo that has the same identifier as my method parameter.

I tried separate the create from the update use cases by adding a separate update API to my service that first reattaches my pojoInstance using a "getHibernateTemplate().update(pojoInstance)" API, but that ends up updating my table even before the validation occurs and I don't want that.

How do I fix my issue? What am I missing?
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

So call saveOrUpdate(), or whatever method will check if it needs an insert or an update. Basically calling save will result in an insert which you don't want because it looks like you loaded the data from the database so there is already a record.

Do you create a new objects and that is what you pass to save, and since you already loaded a record into the Session that matches, you need to merge first. If an object is detached and say has an id of 5, but in the Session there is already an object loaded that has an id of 5, and you don't merge first, then you will see this exact same object.

Mark


Perfect World Programming, LLC - Two Laptop Bag - Tube Organizer
How to Ask Questions the Smart Way FAQ
Madhuri Ramanathan
Greenhorn

Joined: Jun 12, 2008
Posts: 3
Merge() does work (thanks for the idea), except in my case, if I set up my pojo with version optimistic locking strategy, I now get a HibernateOptimisticLockingFailureException. See exception stack trace below. I wonder if in this type of use-case, the right approach is to read the object from the DB and then employ some form of a copy-into the object that is being held by the session before I save it.

Have others encountered similar usages and how have you dealt with the issues around the detached object saving?

org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [Pojo] with identifier [1455148::1]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Pojo#1455148::1]
org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:654)
org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
org.springframework.orm.hibernate3.HibernateTemplate.merge(HibernateTemplate.java:820)
[ June 16, 2008: Message edited by: Madhuri Ramanathan ]
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

Originally posted by Madhuri Ramanathan:
Merge() does work (thanks for the idea), except in my case, if I set up my pojo with version optimistic locking strategy, I now get a HibernateOptimisticLockingFailureException. See exception stack trace below. I wonder if in this type of use-case, the right approach is to read the object from the DB and then employ some form of a copy-into the object that is being held by the session before I save it.

Have others encountered similar usages and how have you dealt with the issues around the detached object saving?

org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [Pojo] with identifier [1455148::1]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Pojo#1455148::1]
org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:654)
org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
org.springframework.orm.hibernate3.HibernateTemplate.merge(HibernateTemplate.java:820)

[ June 16, 2008: Message edited by: Madhuri Ramanathan ]


Yes, there is a complete easy to use approach to detaching objects. You just need to be able to remember and know when an object is being managed by a Session and when it is detached. And how multi-users are changing data that a client might have detached.

So for optimistic locking, if I get a record which last update is "1" and I detach the object and work on the client. As I am doing this someone else updates the same object, so now the update number is "2", the first client then comes back with some changes and you go to merge it. Hibernate will try to see what version is in the database, if it comes back with something that is greater than "1" then it will throw that exception that you are seeing, because someone else beat the first client to the update. That is expected and wanted behavior.

So when you merge and have optimistic locking, then Hibernate will do a special update statement with the version number. If that update returns that if changed/affected no records, then throw an exception, because the database has been changed since the last time that client got the data. It is now stale data.

Mark
Madhuri Ramanathan
Greenhorn

Joined: Jun 12, 2008
Posts: 3
You were right. I had a bug in the way that my detached pojo was handling the version attribute. Once I fixed that, I have my detached pojo working fine with optimistic locking.

Thanks all.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
 
subject: Issue with saving pojo in a transactional wrapper