JPA 2 - Использование EntityManager в JavaSE - пара вопросов - PullRequest
4 голосов
/ 01 ноября 2010

У меня есть пара вопросов относительно использования менеджера сущностей в среде JavaSE.

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

public class Repository<T> implements IRepository<T> {

    private EntityManager em;
    private String persistenceUnitName;

    public Repository(String persistenceUnitName) {
        this.persistenceUnitName = persistenceUnitName;
    }

    @Override
    public T find(Class<T> type, Object id) {
        return em.find(type, id);
    }

    private EntityManager getEntityManager() {
        if (this.em == null) {
            EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);

            em = emf.createEntityManager();
        }

        return em;
    }
    ...
    ...
}

Тогда у меня будут классы, подобные EmployeeRepository, которые будут наследовать Repository. Эти классы репозитория будут созданы в моем слое сервиса.

Это хороший способ инициализации менеджера сущностей? Я начинаю думать, что это не так - кажется, у вас должен быть только один менеджер сущностей на единицу персистентности? Где, как и в этом случае, у вас будет менеджер сущностей для каждого создаваемого вами хранилища ... Как бы вы обеспечили, чтобы у вас был только один менеджер сущностей на единицу персистентности? Кроме того, я заметил, что методы фабрики менеджера сущностей и менеджера сущностей имеют закрытый метод - когда их следует вызывать? На сервере прекратить событие?

Если вам известны какие-либо хорошие источники информации об использовании JPA в JavaSE, я был бы признателен за информацию.

Спасибо!

Ответы [ 2 ]

3 голосов
/ 01 ноября 2010

Почти. Вам нужен только один EntityManagerFactory на единицу персистентности.

Как бы вы обеспечили наличие только одного EntityManagerFactory на единицу персистентности?

Обычно разработчики создают вспомогательный класс с одноэлементным EntityManagerFactory, например

public class EntityManagerFactoryHelper {

    private static EntityManagerFactory factory;

    static {
        try {
           // Set up factory right here
        } catch(ExceptionInInitializerError e) {
            throw e;
        }
    }

    public static EntityManagerFactory getFactory() {
        return this.factory;
    }

}

EntityManager , с другой стороны, используется для взаимодействия с набором экземпляров управляемого объекта, который называется контекстом постоянства.

Если вы хотите знать, почему я использую ErrorInInitializerError , его API понятен

Сигналы о том, что в статическом инициализаторе

произошло непредвиденное исключение

...

Это хороший способ инициализации менеджера сущностей?

Ну, сервисный уровень используется для разграничения границы транзакции . Таким образом, для каждого варианта использования , вы можете создать свой EntityManager и передавать по ссылке для каждого колаборатора , необходимого для выполнения вашего варианта использования.

public static br.com.helper.EntityManagerFactoryHelper.getFactory;

public EmployeeService {

    public void doSomething() {
        EntityManager eManager = getFactory().createEntityManager();
        eManager.getTransaction().begin();

        EmployeeRepository repository = new EmployeeRepository(eManager);

        eManager.getTransaction().commit();
    }

}

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

    public void forEachUseCase() {
        // Create an EntityManager
        // Begin a Transaction

        EmployeeRepository repository = new EmployeeRepository(eManager);

        // And finally, commit
    }

Вы можете положиться на Spring , чтобы помочь вам избавиться от этого стандартного кода.

1 голос
/ 19 марта 2017

Brian

Это нормально, чтобы поделиться EntityManagerFactory, но это не нормально, чтобы поделиться EntityManager. См. Викибук Java Persistence .

Более современный подход - создавать синглтоны с перечислениями. Итак, предположим, что вы не собираетесь менять имена своих персистентных юнитов (я бы ожидал, что этого не произойдет) ...

Так в идеале ...

  1. Использовать синглтон для экземпляра EntityManagerFactory на единицу персистентности.
  2. Создавайте новый менеджер сущностей при каждом вызове, чтобы получить его, и не делитесь им.

Использование перечисления для одноэлементного механизма обеспечивает ... ( Effective Java Second edition )

  1. Будучи лаконичным
  2. Предоставляет оборудование для сериализации бесплатно
  3. Предотвращает множественное создание EntityManagerFactory без проблем с синхронизацией. Это происходит потому, что конструкторы enum вызываются во время загрузки класса и не могут быть вызваны вашим кодом.
  4. Гарантирует, что EntityManager не является общим, если программист не сделает неправильный выбор.
public enum PersistenceUnitFactory
{
    PERSISTENCE_UNIT_1("persistenceUnit1"),
    PERSISTENCE_UNIT_2("persistenceUnit2");

    private final EntityManagerFactory emf;
    /**
     * Maps the persistence unit name to this instance of the enum.
     *
     * @param persistenceUnitName the name of the peristence unit in
     *                            persistence.xml
     *
     * @see #getPersistenceUnitName()
     */
    PersistenceUnitFactory(final String persistenceUnitName)
    {
        emf = Persistence.createEntityManagerFactory(persistenceUnitName);
    }

    /**
     * Creates a new {@link EntityManager}.  NEVER share this across threads.
     * 
     * @return a new {@link EntityManager}
     */
    EntityManager createEntityManager()
    {
        return emf.createEntityManager();
    }
}

Тогда это так же просто, как запросить EntityManager ...

PersistenceUnitFactory.PERSISTENCE_UNIT_1.createEntityManager();

Вы можете добавлять больше единиц персистентности по мере необходимости.

...