【问题标题】:Best Practice instantiating EntityManager实例化 EntityManager 的最佳实践
【发布时间】:2016-07-26 13:37:02
【问题描述】:

我在另一个主题 (Empty List (not Table) at ManyToMany-Relation) 中遇到问题,想知道我对 EntityManager 的使用是否正确。那么使用 EntityManager 的最佳方式应该是什么?几年前,我读到了一些关于 DAO 模式的东西(比如http://www.oracle.com/technetwork/java/dataaccessobject-138824.html),从那以后我就开始使用了。但是现在当我想加入 WebServices 课程时,我认为“服务层”会更好,所以我建立了一个类似的课程

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("role")
public class RoleService {

@GET
@Path("ping")
@Produces(MediaType.TEXT_PLAIN)
public String helloWorld() {
    return "REST-Web-Service ready for Role.class!";
}

public static void create(Role object) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    em.persist(object);
    tx.commit();
    em.close();
}

public static void update(Role object) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    em.merge(object);
    tx.commit();
    em.close();
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("id/{id}")
public static Role getRole(@PathParam("id") Integer id) {
    return load(id);
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("name")
public static String getName(@QueryParam("id") Integer id) {
    Role role = findById(id);
    if (role != null) {
        return "[\n   {\n      \"id\":"+id+",\n      \"type\":\"role\",\n      \"name\": \"" + role.getName() + "\",\n      \"query\":\"success\"\n   }\n]";
    }
    return "[\n   {\n      \"id\":"+id+",\n      \"type\":\"role\",\n      \"query\":\"failed\"\n   }\n]";
}

public static Role findById(Integer id) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    Role object = em.find(Role.class, id);
    tx.commit();
    em.close();
    return object;
}

public static Role load(Integer id) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    Role objectResult = em.find(Role.class, id);
    tx.commit();
    em.close();
    return objectResult;
}

public static Role load(Role object) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    Role objectResult = em.find(Role.class, object.getId());
    tx.commit();
    em.close();
    return objectResult;
}

public static void deleteById(Integer id) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    em.remove(em.find(Role.class, id));
    tx.commit();
    em.close();
}

// @DELETE
// @Path("{id}")
public static void delete(Role object) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    em.remove(em.find(Object.class, object.getId()));
    tx.commit();
    em.close();
}

public static List<Role> findByName(String name) {
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    List<Role> list = em.createQuery("SELECT r FROM Role r WHERE r.name LIKE :name").setParameter("name", "%" + name + "%").getResultList();
    tx.commit();
    em.close();
    return list;
}

}

PersistenceUtil 是

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class PersistenceUtil {

/*
 * Name of persistence unit which MUST correlate to persistence-unit name in persistence.xml
 */
private static final String PERSISTENCE_UNIT_NAME = "RoleModel";


private static final EntityManagerFactory entityManagerFactory;
static {
    try {
        entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
    } catch (Throwable ex) {
        System.err.println("EntityManagerFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

public static EntityManagerFactory getEntityManagerFactory() {
    return entityManagerFactory;
}

}

但在文章Entity manager best practices 中似乎有所不同。我应该在哪里实例化 EntityManager?我应该使用更好的注释吗?更好的 Sigleton 级?每种方法都用它可以吗?

你怎么看?

【问题讨论】:

  • CDI(jboss 或 spring)是一种现代且非常优雅的方式。

标签: java json rest jpa jax-rs


【解决方案1】:

我认为最常用的方法是首先使用 CDI(上下文和依赖注入)。

使用 CDI,您的 DAO 获取由应用程序容器(Java 应用程序服务器,例如 Glassfish)注入的 EntityManager。它可能看起来像这样:

@Dependent
public class FooDAO {

    @PersistenceContext
    private EntityManager em;

    public FooEntity find(final Number id) throws NoResultException {
        return em.find(FooEntity.class, id);
    }

    public List<FooEntity> findAll() {
        return em.createNamedQuery("FooEntity.findAll", FooEntity.class).getResultList();
    }

    // ...
}

CDI 容器会记录 @PersistenceContext 注释,并且实体管理器会被实例化,因此您无需担心与它相关的任何事情。事务也由应用服务器管理。您可能已经有一个 persistence.xml,您可以在其中设置所有与数据库相关的设置。顺便说一下,对于服务器管理的持久性,它需要定义transaction-type="JTA"。查看网络上的大量示例。

在您的服务或业务逻辑类中(取决于您想要多少层),您可以像这样使用您的 DAO 类:

@Stateless
public class FooManager {

    @Inject
    private FooDAO fooDAO;


    public List<FooEntity> getFoos() {
        return fooDAO.findAll();
    }

    // ...
}

注解@Dependent@Stateless是两个of many CDI offers。根据这一点,CDI 管理器创建您的类的一个或多个实例。流行的选择包括@ViewScoped@SessionScoped@ApplicationScoped。搜索网络时,不要被 JSF 或 Seam 的注释弄糊涂。你不想使用那些!您想要使用 JSF 的唯一东西是 @Named 注释,并且您只将它应用于支持 bean(负责查看的 java 类)。 EJB 注释也可以。它们大多与 CDI 兼容。

上面的代码和建议是关于 Java EE 的。一些框架正在使用它们自己的注释和模式。最值得注意的是 Spring 和 Play 框架。对于这些,请参考精美的文档。

【讨论】:

    【解决方案2】:

    无论您使用什么模式,都有一个始终有效的规则。

    只创建一次 EntityManagerFactory。 EntityManager 可以在每个事务上创建,因为它是一个廉价的对象。

    就模式而言,是的,DAO 和存储库模式及其变体最为常见。

    【讨论】:

      【解决方案3】:

      我完全同意 CDI 方法是最好的。控制的反转减少了耦合,但保持了系统的凝聚力。您也不必担心分配/解除分配管理器。

      您还可以在您的 persistence.xml 中拥有 N 个持久性单元,并且您可以将 EntityManager 直接分配给该单元。此外,您可以将我在此处设置的上下文类型设置为事务。

      @PersistenceContext(unitName = PersistenceStartupService.BJOND_STORE, type=PersistenceContextType.TRANSACTION)
      private EntityManager entityManager;
      

      我鼓励人们将大型架构分解为单独的持久性单元,这也有助于对某些表进行防火墙访问。我通常将我的 IdentityManager (PicketLink) 作为一个单独的持久性单元。

      【讨论】:

        猜你喜欢
        • 2010-12-30
        • 1970-01-01
        • 1970-01-01
        • 2010-10-07
        • 2013-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-20
        相关资源
        最近更新 更多