tags:

views:

750

answers:

2

Hi, new to Spring and here @stackoverflow

I'm building an stand-alone Inventory & Sales tracking app (Apache Pivot/Spring/JPA/Hibernate/MySQL) for a distributor business.

So far I think everything is CRUD, so I plan to have a base class with everything @Transactional.

Then I got a problem with my save generic method. Does persist and merge method of the EntityManager from Spring have a difference?

I tried running and called the save for both inserting and updating and it worked fine(I think spring automatically refreshes the entity every time I call my save method // saw the hibernate queries being logged, is this right?).

@Transactional
public abstract class GenericDAO {

    protected EntityManager em;

//  em getter+@PersistenceContext/setter

    public void save(T t) {
//        if (t.getId() == null) // create new
//        {
//            em.persist(t);
//        } else // update
//        {
            em.merge(t);
//        }
    }
}

And btw, having a setup like this, I won't be much compromising performance right? Like calling salesDAO.findAll() for generating reports ( which does not need to be transactional, right? ).

thanks!!!

+4  A: 

This SO question is a good discussion of persist vs. merge, and the accepted answer explains it pretty well. The other answer also links to a good blog post about this.

According to the first reply in this other post, it sounds like it would be possible to call merge for both saving and updating an entity, but that's not how I've done it. In my Spring/JPA apps, I just have my DAOs extend JpaDaoSupport and use the getJpaTemplate() in the following way.

/**
 * Save a new Album.
 */
public Album save(Album album) {
 getJpaTemplate().persist(album);
 return album;
}

/**
 * Update an existing Album.
 */
public Album update(Album album) {
 return getJpaTemplate().merge(album);
}
Kaleb Brasee
I guest this is the simplest way to go.So if I have JpaDaoSupport, and I get an entity from it, any changes will be automatically commited?I think I'll have two variants of save method, one that persists and one that calls flush. Any comment on this?
thirdy
Do you mean automatic as in committed without a save or update? If so, I wouldn't think so, I always just call save on a new entity or update on an existing one to persist. I've never needed to call the flush method, but my DB access is pretty simple for any given request.
Kaleb Brasee
I'll have to give up trying Spring for now. Just curious, how does Grails improve on this? I won't have to encounter problems like these in Grails right?
thirdy
+3  A: 

The link to the other SO question Kaleb posted does do a good job of covering the differences and gotchas of persist() vs merge(). However, I've always just implemented my Dao classes with one save() method that only calls merge() to handle both inserts and updates, and I've never run into any of the persist() vs merge() gotchas.

As far as performance and transactional methods: Using @Transactional on methods that are only read operations won't really impact performance, though I prefer to use the annotations on method level just so I can easily tell which methods are updates and which are reads. You can do this by setting the readOnly attribute on the @Transactional annotation.

If you follow a naming convention in your methods (i.e. any read method always starts with getXXX), you could also use poincut syntax in your Spring config file to automatically make this differentiation:

  <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="get*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

See the Spring documentation on Transactions for more info.

Also, I usually put the @Transactional attributes one level above my Dao classes, in a service layer. Methods on the Dao classes are then distinct database operations for each method call, while the service methods can do a single commit/rollback for a series of updates.

Jason Gritman
thanks for answering. I think I'll stick to pure JPA, (I don't have much need for flexibility)
thirdy