跳转到内容

Java 持久化/运行时

来自 Wikibooks,开放的书籍,开放的世界

在映射完对象模型后,持久化开发的第二步是从应用程序访问和处理对象,这被称为持久化的运行时使用。各种持久化规范都有不同的运行时模型。最常见的模型是拥有一个运行时 API;运行时 API 通常会定义 API 用于连接到数据源、查询和事务。

实体管理器

[编辑 | 编辑源代码]

JPA 提供了由 javax.persistence 包定义的运行时 API。主要的运行时类是 EntityManager 类。EntityManager 提供用于创建查询、访问事务以及查找、持久化、合并和删除对象的 API。JPA API 可用于任何 Java 环境,包括 JSE 和 JEE。

EntityManager 可以通过 EntityManagerFactory 创建,也可以注入到 EJB SessionBean 中的实例变量中,也可以在 JEE 服务器中的 JNDI 中查找。

JPA 在 Java 标准版 (JSE) 和 Java 企业版 (JEE) 中的使用方式不同。

Java 标准版

[编辑 | 编辑源代码]

在 Java SE 中,EntityManager 是通过 JPA Persistence 类中的 createEntityManagerFactory API 访问的。持久化单元名称 传递给 createEntityManagerFactory,这是在持久化单元的 persistence.xml 文件中给定的名称。所有 Java SE JPA 应用程序都必须定义 persistence.xml 文件。该文件定义了持久化单元,包括名称、类、orm 文件、数据源、特定于供应商的属性。

JPA 1.0 没有定义在 Java SE 中指定如何连接到数据库的标准方法。每个 JPA 提供商都定义了自己的持久化属性,用于设置 JDBC 驱动程序管理器类、URL、用户和密码。JPA 有一种标准方法来设置 DataSource JNDI 名称,但这主要用于 JEE。

JPA 2.0 在 Java SE 中定义了用于连接到 JDBC 的标准持久化单元属性。这些包括 javax.persistence.jdbc.driverjavax.persistence.jdbc.urljavax.persistence.jdbc.userjavax.persistence.jdbc.password

JPA 应用程序通常需要打包到持久化单元 jar 文件中。这是一个普通的 jar 文件,它在 META-INF 目录中包含 persistence.xml 文件。通常,JPA 提供商会要求在 Java SE 中执行一些特殊操作来启用某些功能,例如延迟获取,例如 jar 的静态编织(字节码处理),或使用 Java 代理 JVM 选项。

在 Java SE 中,当您的应用程序不再使用 EntityManager 时,必须关闭它。EntityManager 的生命周期通常是每个客户端或每个请求。EntityManagerFactory 可以由多个线程或用户共享,但 EntityManager 不应该共享。

JPA 1.0 persistence.xml 文件示例

[编辑 | 编辑源代码]
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd"
                version="1.0">
    <persistence-unit name="acme" transaction-type="RESOURCE_LOCAL">
        <!-- EclipseLink -->
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <!-- TopLink Essentials -->
        <!--provider>oracle.toplink.essentials.PersistenceProvider</provider-->

        <!-- Hibernate 3.x -->
        <!--provider>org.hibernate.ejb.HibernatePersistence</provider-->

        <!-- Hibernate -->
        <!--provider>org.hibernate.jpa.HibernatePersistenceProvider</provider-->

        <!-- Apache OpenJPA -->
        <!--provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider-->

        <!-- DataNucleus-->
        <!--provider>org.datanucleus.jpa.PersistenceProviderImpl</provider-->

        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.jdbc.driver" value="org.acme.db.Driver"/>
            <property name="eclipselink.jdbc.url" value="jdbc:acmedb://127.0.0.1/acme"/>
            <property name="eclipselink.jdbc.user" value="wile"/>
            <property name="eclipselink.jdbc.password" value="elenberry"/>
        </properties>
    </persistence-unit>
</persistence>

JPA 2.0 persistence.xml 文件示例

[编辑 | 编辑源代码]
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd"
                version="2.0">
    <persistence-unit name="acme" transaction-type="RESOURCE_LOCAL">
         <!-- EclipseLink -->
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <!-- TopLink Essentials -->
        <!--provider>oracle.toplink.essentials.PersistenceProvider</provider-->

        <!-- Hibernate 3.x -->
        <!--provider>org.hibernate.ejb.HibernatePersistence</provider-->

        <!-- Hibernate -->
        <!--provider>org.hibernate.jpa.HibernatePersistenceProvider</provider-->

        <!-- Apache OpenJPA -->
        <!--provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider-->

        <!-- DataNucleus -->
        <!--provider>org.datanucleus.jpa.PersistenceProviderImpl</provider-->

        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.acme.db.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:acmedb://127.0.0.1/acme"/>
            <property name="javax.persistence.jdbc.user" value="wile"/>
            <property name="javax.persistence.jdbc.password" value="elenberry"/>
        </properties>
    </persistence-unit>
</persistence>

从 EntityManagerFactory 访问 EntityManager 的示例

[编辑 | 编辑源代码]
EntityManagerFactory factory = Persistence.createEntityManagerFactory("acme");
EntityManager entityManager =  factory.createEntityManager();
...
entityManager.close();

Java 企业版

[编辑 | 编辑源代码]

在 Java EE 中,EntityManagerEntityManagerFactory 可以通过在 JNDI 中查找或注入SessionBean 中来获取。要在 JNDI 中查找 EntityManager,它必须发布到 JNDI 中,例如通过 SessionBeanejb-jar.xml 文件中的 <persistence-context-ref>。要注入 EntityManagerEntityManagerFactory,使用 @PersistenceContext@PersistenceUnit 注解。

在 Java EE 中,EntityManager 可以是管理的(容器管理的)或非管理的(应用程序管理的)。管理的 EntityManager 与应用程序管理的 EntityManager 具有不同的生命周期。管理的 EntityManager 不应该关闭,并且与 JTA 事务集成,因此不能使用本地事务。在每个 JTA 事务边界,通过管理的 EntityManager 读取或持久化的所有实体都会变为分离状态。在 JTA 事务之外,管理的 EntityManager 的行为有时很奇怪,因此通常应该在 JTA 事务中使用它。

非管理的 EntityManager 是指通过 EntityManagerFactory 或直接从 Persistence 创建的 EntityManager。非管理的 EntityManager 必须关闭,并且通常不与 JTA 集成,但这可以通过 joinTransaction API 来实现。非管理的 EntityManager 中的实体在事务完成后不会变为分离状态,并且可以在随后的事务中继续使用。

Java EE JPA persistence.xml 文件示例

[编辑 | 编辑源代码]
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd"
                version="1.0">
    <persistence-unit name="acme" transaction-type="JTA">
        <jta-data-source>jdbc/ACMEDataSource</jta-data-source>
    </persistence-unit>
</persistence>

具有持久化上下文的示例 SessionBean ejb-jar.xml 文件

[编辑 | 编辑源代码]
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
          version="3.0">
    <enterprise-beans>
        <session>
            <ejb-name>EmployeeService</ejb-name>
            <business-remote>org.acme.EmployeeService</business-remote>
            <ejb-class>org.acme.EmployeeServiceBean</ejb-class>
            <session-type>Stateless</session-type>
            <persistence-context-ref>
                <persistence-context-ref-name>persistence/acme/entity-manager</persistence-context-ref-name>
                <persistence-unit-name>acme</persistence-unit-name>
            </persistence-context-ref>
            <persistence-unit-ref>
                <persistence-unit-ref-name>persistence/acme/factory</persistence-unit-ref-name>
                <persistence-unit-name>acme</persistence-unit-name>
            </persistence-unit-ref>
        </session>
    </enterprise-beans>
</ejb-jar>

从 SessionBean 中在 JNDI 中查找 EntityManager 的示例

[编辑 | 编辑源代码]
InitialContext context = new InitialContext(properties);
EntityManager entityManager =  (EntityManager)context.lookup("java:comp/env/persistence/acme/entity-manager");
...

从 SessionBean 中在 JNDI 中查找 EntityManagerFactory 的示例

[编辑 | 编辑源代码]
InitialContext context = new InitialContext(properties);
EntityManagerFactory factory =  (EntityManagerFactory)context.lookup("java:comp/env/persistence/acme/factory");
...

在 SessionBean 中注入 EntityManager 和 EntityManagerFactory 的示例

[编辑 | 编辑源代码]
@Stateless(name="EmployeeService", mappedName="acme/EmployeeService")
@Remote(EmployeeService.class)
public class EmployeeServiceBean implements EmployeeService {
    
    @PersistenceContext(unitName="acme")
    private EntityManager entityManager;

    @PersistenceUnit(unitName="acme")
    private EntityManagerFactory factory;
    ...
}

在实体中查找 EJBContext 的示例

[编辑 | 编辑源代码]

(对 审计 有用)

protected EJBContext getContext() {
    try {
        InitialContext context = new InitialContext();
        return (EJBContext)context.lookup("java:comp/EJBContext");
    } catch (NamingException e) {
        throw new EJBException(e);
    }
}

无状态会话 Bean

[编辑 | 编辑源代码]

有状态会话 Bean

[编辑 | 编辑源代码]
华夏公益教科书