JPA/Hibernate problem with competition and persistence in the JRE

Asked

Viewed 774 times

2

I am working on a project to create a simple server running over Java SE. I am using JPA + Hibernate to perform persistence, but competing routines are a problem. I am spending a lot of time trying to solve the problems generated by Hibernate without having a significant return. I would like to know from fellow Members already existing solutions to solve the Java SE competition problems, such as the container-Managed EntityManager of J2EE.

Problems:

  • Always close the EntityManager.
  • Instances of divergent objects in instances of EntityManager different.
  • Competing operations with EntityManager different generating persistence error.

1 answer

0


Let’s start with these two items:

  • Instances of divergent objects in instances of EntityManager different.
  • Competing operations with EntityManager different generating persistence error.

NEVER use the same EntityManager in different threads. The EntityManager was designed to live and die confined within the thread that created it.

I recommend studying how to make the lock of experiences. It is worth studying the concepts of optimistic lock (optimistic lock) and pessimistic lock (pessimistic lock). In the places where you prefer the optimistic lock, remember the note @Version. I won’t go into more detail here, because that would be enough to write a few book chapters and the idea is just to show you which is the way to find what you want.

In addition, it is worth remembering that each instance of an entity can only be managed by a single EntityManager, and because of this it is not correct to share these instances among several EntityManagers, which also means you have to be very careful if you’re going to share them in more than one thread. One way to do this is kind of like this:

MinhaEntidade veioDeOutraThread = ...;
MinhaEntidade minhaEntidadeNestaThread = em.find(MinhaEntidade.class, veioDeOutraThread.getId());

A safe way to work with this would be to never share any object that is touched by JPA between different threads that can access the database directly.

  • Always close the EntityManager.

The obvious thing is to use the old try-finally, but maybe you want something more magical. In this case I can suggest you from something more or less like this (Java 8):

 private static final EntityManagerFactory EMF = ...;

 private final ThreadLocal<EntityManager> ativo = new ThreadLocal<>();

 public <E> E transact(Function<EntityManager, E> func) {
     EntityManager em = ativo.get();
     if (em != null) return func.apply(em);
     em = EMF.createEntityManager();
     try {
         ativo.set(em);
         boolean success = false;
         EntityTransaction et = em.getTransaction();
         try {
             et.begin();
             E ret = func.apply(em);
             success = !et.getRollbackOnly();
             return ret;
         } finally {
             if (et.isActive()) {
                 if (success) {
                     et.commit();
                 } else {
                     et.rollback();
                 }
             }
         }
     } finally {
         ativo.set(null);
         em.close();
     }
 }

If you are using Java 7 or lower, it shouldn’t be too difficult to adapt this code to your needs. If you intend to do your method transact throw some verified exception, so the best thing to do is to use a customized functional interface.

This above code can be improved to prevent EntityManager be recreated multiple times in the same Thread if you don’t close it and use a em.clear() before starting any operation and/or after finishing them. However, if this is not done in a very precise way, you can introduce competition bugs in the application, while opening and closing several times the way it is, at most it harms a little the performance.

Also, you might notice that the above code emulates the semantics of the transaction scope required from EJB/Java EE (at least I think it emulates, unless I’ve done something stupid or forgotten something). It is not very difficult to modify it to emulate other scopes such as requires new, Mandatory, etc..

Browser other questions tagged

You are not signed in. Login or sign up in order to post.