Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Transactional merge and persist question

Tags:

java

spring

jpa

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!!!

like image 821
thirdy Avatar asked Oct 18 '09 04:10

thirdy


2 Answers

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);
}
like image 122
Kaleb Brasee Avatar answered Oct 29 '22 17:10

Kaleb Brasee


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.

like image 44
Jason Gritman Avatar answered Oct 29 '22 17:10

Jason Gritman