5

我有几个关于在 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。这些存储库类将在我的服务层中创建。

这是初始化实体管理器的好方法吗?我开始认为它不是 - 似乎每个持久性单元应该只有一个实体管理器?在这种情况下,您将为您创建的每个存储库都有一个实体管理器……您将如何确保每个持久性单元只有一个实体管理器?另外,我注意到实体管理器和实体管理器工厂方法有一个 close 方法 - 什么时候应该调用它们?在服务器终止事件上?

如果您知道有关在 JavaSE 中使用 JPA 的任何良好资源,我将不胜感激。

谢谢!

4

2 回答 2

4

几乎。每个持久性单元只需要一个 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来帮助您摆脱这种样板代码。

于 2010-11-01T05:56:11.487 回答
2

布赖恩,

EntityManagerFactory 可以共享,EntityManager 不能共享。请参阅Java 持久性 wikibook

更现代的方法是用枚举做单例。因此,假设您不希望更改持久性单元名称(我希望无论如何都不会发生)...

所以理想...

  1. 每个持久性单元为 EntityManagerFactory 实例使用一个单例。
  2. 在每次调用时创建一个新的实体管理器以检索一个,并且不要共享它们。

使用枚举作为单例机制提供...(有效的 Java 第二版

  1. 简洁
  2. 免费提供序列化机器
  3. 防止 EntityManagerFactory 的多个实例化而没有同步问题。发生这种情况是因为枚举构造函数在类加​​载时被调用,并且不能被您的代码调用。
  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();

您可以根据需要添加更多持久性单元。

于 2017-03-19T03:54:34.150 回答