Как создать потокобезопасный EntityManagerFactory? - PullRequest
7 голосов
/ 14 сентября 2010

Я работаю над приложением, которое должно выполнять некоторые операции с базой данных.

Я создал статическую переменную для EntityManagerFactory и инициализировал ее в методе, который вызывается приложением

 if (emf == null){
                    emf = Persistence.createEntityManagerFactory("example");
                }

try {
            em = emf.createEntityManager();
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }

безопасен ли этот поток? если я создаю EntityManagerFactory в синхронизированном блоке, число ожидающих потоков увеличивается и приводит к сбою приложения.

Я посмотрел документы, чтобы определить, является ли Persistence.createEntityManagerFactory потокобезопасным без какого-либо успеха.

Пожалуйста, укажите мне правильные ресурсы.

Ответы [ 5 ]

11 голосов
/ 14 сентября 2010

Простой способ «решить» это - использовать вспомогательный класс (а-ля HibernateUtil) и инициализировать EntityManagerFactory в статическом блоке инициализации.Примерно так:

public class JpaUtil { 
    private static final EntityManagerFactory emf;

    static {
        try {
            factory = Persistence.createEntityManagerFactory("MyPu");
        } catch (Throwable ex) {
            logger.error("Initial SessionFactory creation failed", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

   ...

}

И «проблема» исчезла.

3 голосов
/ 05 октября 2010

Я не вижу проблем с подходом статического блока. Или вы можете сделать то же самое следующим образом, который представляет собой шаблон Singleton с проверкой двойной блокировки

public class JPAHelper {

 private static JPAHelper myHelper = new JPAHelper();
 private static EntityManagerFactory myFactory = null;

 /**
  * Private constructor. Implementing synchronization with double-lock check
  */
 private JPAHelper() {

  if(myFactory == null) {
   synchronized (JPAHelper.class) {

    // This second check will be true only for the first thread entering the block incase 
    // of thread race
    if(myFactory == null) {
     myFactory = Persistence.createEntityManagerFactory("MyUnit");
    }
   }
  }
 }

 /**
  * Static Accessor Method
  * @return
  */
 public static JPAHelper getInstance() {
  if(myHelper == null) {
   myHelper = new JPAHelper();
  }
  return myHelper;
 }


 public EntityManagerFactory getJPAFactory() {
  return myFactory;
 }

И тебе позвонят

EntityManager myManager = JPAhelper.getInstance().getJPAFactory().createEntityManager();
1 голос
/ 14 сентября 2010

Независимо от того, является ли createEntityManagerFactory() поточно-ориентированным или нет, вам нужна некоторая стратегия, чтобы она вызывалась только один раз. Другими словами, этот вопрос не имеет значения, потому что вы должны убедиться, что только один поток вызывает его.

Если простое ожидание того, что другой поток создаст фабрику, приведет к сбою вашего приложения, что произойдет, когда каждый поток создаст свой собственный, что затруднит работу других потоков в процессе?

Код, который вы показываете, должен быть внутри блока synchronized, или он не является потокобезопасным.

1 голос
/ 14 сентября 2010

Вам необходимо установить блокировки на объекте при создании ЭДС.Вы можете установить блокировки на самом объекте ЭДС, но это не лучшая практика.Создайте еще один объект:

private object factoryLockObject = new object();

и наложите на него блокировки при создании фабрики

lock(factoryLockObject)
{
   if (emf == null)
   {
      emf = Persistence.createEntityManagerFactory("example");
   }
}

Это поможет?

0 голосов
/ 05 февраля 2013

Ответ на вопрос: ДА, createEntityManagerFactory () является поточно-ориентированным на основе документации класса, результатов исходного кода и реальных приложений.

Ответ синглтон-паттерна является наиболее правильным, чтобы избежать дополнительного вызова для эффективного извлечения одного фабричного дескриптора, но учтите, что нет необходимости в двойной проверке блокировки, как было отмечено ранее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...