Home > Back-end >  Are there performance issues when using both an EntityManager and Spring Repository in the same tran
Are there performance issues when using both an EntityManager and Spring Repository in the same tran

Time:05-31

I have a case where my Foo contains an object Bar, and if that Bar object does not already exist in the BarRepository, I want to persist it first and then continue to save the Foo object (don't need to do this when first creating the Foo object, but for some reason need to do this when updating it with a new Bar object).

I am wondering if it is either considered bad practice or any significant performance issues when combining both the an EntityManager (to update) and a Spring Repository (to check if something exists) together.

Here is my particular case:

@Service
@AllArgsConstructor
public class FooService {

  private final FooRepository fooRepository;
  private final BarRepository barRepository;
  private final EntityManagerFactory entityManagerFactory;

  // works fine
  public Foo update(long id, Consumer<Foo> consumer) {
    var foo = get(id);
    updateFields(foo, consumer);
    var entityManager = entityManagerFactory.createEntityManager();
    var transaction = entityManager.getTransaction();
    transaction.begin();
    if (foo.getBar() != null) {
      if (!barRepository.existsById(foo.getBar().getId())) {// option 1
        entityManager.persist(foo.getBar());
      }
    }
    var update = entityManager.merge(foo);
    transaction.commit();
    entityManager.close();
    return update;
  }

  // doesnt work yet, but the idea is this
  public Foo update(long id, Consumer<Foo> consumer) {
    var foo = get(id);
    updateFields(foo, consumer);
    var entityManager = entityManagerFactory.createEntityManager();
    var transaction = entityManager.getTransaction();
    transaction.begin();
    if (foo.getBar() != null) {
      var barId = foo.getBar().getId();
      if (entityManager // option 2
              .createNativeQuery(
                      "SELECT b FROM bar b WHERE b.text = ?1 AND b.duration = ?2")
              .setParameter(1, barId.getText()())
              .setParameter(2, barId.getDuration())
              .getSingleResult()
              == null) {
        entityManager.persist(foo.getBar());
      }
    }
    var update = entityManager.merge(foo);
    transaction.commit();
    entityManager.close();
    return update;
  }

}

Out of these two methods, to me the first one is much cleaner to me because the checking of the the Foo entity is a small, one liner, compared to the other one, but I want to follow whatever the standard is.

CodePudding user response:

Spring Data JPA is build on JPA and uses the EntityManager internally. Spring Data never aimed at completely removing JPA from your code base. Its goal is to make the easy stuff trivial and comfortable while not getting in your way when you need to use it directly.

So using the EntityManager is completely fine and actually expected for many non trivial applications.

But code accessing the EntityManager lives on a different abstraction layer than the code using a repository. I therefore recommend to move your EntityManager using code into custom methods of your repositories.

  • Related