• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

Issue with saving pojo in a transactional wrapper

 
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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?
 
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Madhuri Ramanathan
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
permaculture is giving a gift to your future self. After reading this tiny ad:
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic