Home > Fixing Spring + JPA "Removing a detached instance" exception

Fixing Spring + JPA "Removing a detached instance" exception
Posted by Kaleb Brasee on Saturday, January 17th, 2009 at 07:56 PM

I've been working on an update to this site that adds blogging & commenting features. It's a Spring + JPA site, so I created a Post object and a PostDAO and built all the new features using those classes. Everything worked perfectly until I implemented the delete controller. When trying to delete a Post, I was getting the following exception:

org.springframework.dao.InvalidDataAccessApiUsageException: Removing a detached instance com.musicstore.model.Post

I debugged the exception, searched all over the place and couldn't figure what was causing the exception, which was occurring within a getJpaTemplate().remove(post) call. After an hour or two of fruitless googling, I decided to read up on JpaSupport (which the PostDAO extends) and look more closely at my code. I finally realized what the problem was when I noticed that JpaSupport provides callbacks when you need to access an EntityManager directly – but I wasn't using them...

The problem originated in a find method that was happening before the delete. In this method I need to specify how many results to return, and so JpaSupport's find wrapper methods weren't sufficient – I need to access the EntityManager directly. So I was getting an EntityManager like this:

public List findSetOfPosts(Integer firstResult, Integer maxResults) {
   EntityManager em = getJpaTemplate().getEntityManagerFactory().createEntityManager();
   // do stuff with the EntityManager...
}

This created an EntityManager, and the find query did work. However, when I called getJpaTemplate().remove(post), the post I had found was now detached. The solution was to get the EntityManager with a JpaCallback so that JpaSupport can manage the EntityManager correctly, like so:

public List findSetOfPosts(final Integer firstResult, final Integer maxResults) {
   return (List) getJpaTemplate().execute(new JpaCallback() {
      @Override
      public Object doInJpa(EntityManager em) throws PersistenceException {
         // do stuff with the EntityManager...
      }
   }
}

After I switched to this method of obtaining an EntityManager, everything worked perfectly.