gae 数据存储的 jpa 说明

将 JDO 与 App Engine 配合使用

Java 持久性 API (JPA) 是一个用于将包含数据的对象存储在关系数据库中的标准接口。该标准定义用于对 Java 对象进行批注、通过查询检索对象,并使用事务与数据库交互的接口。使用 JPA 接口的应用程序可以在不使用任何供应商特定的数据库代码的情况下使用不同的数据库。JPA 使您的应用程序可轻松地在不同的数据库供应商之间移植。

App Engine Java SDK 包括针对 App Engine 数据存储区的 JPA 1.0 的实现。该实现基于 DataNucleus 访问平台。由于 JPA 提供一个标准接口和关系数据库交互,而 App Engine 数据存储区并非一个关系数据库,因此存在 App Engine 实现不支持的 JPA 功能。在可能的情况下,我们已尽力呼吁注意这些功能。

有关 JPA 的详细信息,请参阅访问平台 1.1 文档。详细而言,请参阅 JPA 映射和 JPA API

设置 JPA

要使用 JPA 访问数据存储区,App Engine 应用程序需进行以下设置:

  • JPA 和数据存储区 JAR 必须位于应用程序的 war/WEB-INF/lib/ 目录。
  • 命名为 persistence.xml 的配置文件必须位于应用程序的 war/WEB-INF/classes/META-INF/ 目录中,配置为使 JPA 使用 App Engine 数据存储区。
  • 项目的构建过程必须对编译的数据类执行后编译“增强”步骤以使其与 JPA 实现相关联。

如果使用的是 Eclipse Google 插件,则第一项和第三项已为您处理。新项目向导将 JPA 和数据存储区 JAR 放置在正确的位置上,构建过程自动执行“增强”步骤。您仍必须手动创建 persistence.xml 并将其放置在 war/WEB-INF/classes/META-INF/ 中。很快将更新该插件,以便可以自动执行此操作。

如果使用 Apache Ant 构建项目,您可以使用 SDK 内含的 Ant 任务来执行增强步骤。您必须在设置项目时复制 JAR 并创建配置文件。有关 Ant 任务的详细信息,请参阅使用 Apache Ant

复制 JAR

JPA 和数据存储区 JAR 内含在 App Engine Java SDK 中。您可以在 appengine-java-sdk/lib/user/orm/ 目录中找到。

将 JAR 复制到您的应用程序的 war/WEB-INF/lib/ 目录中。

确保 appengine-api.jar 也在 war/WEB-INF/lib/ 目录中。(可能已在创建项目时进行过复制)App Engine DataNucleus 插件使用此 JAR 访问数据存储区。

创建 persistence.xml 文件

JPA 接口需要应用程序的 war/WEB-INF/classes/META-INF/ 目录中的命名为 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
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>

</persistence>

增强数据类

JPA 的 DataNucleus 实现在构建过程中使用后编译“增强”步骤使数据类与 JPA 实现相关联。

如果使用的是 Apache Ant,则 SDK 包括一个 Ant 任务来执行此步骤。有关 Ant 任务的详细信息,请参阅使用 Apache Ant

您可通过命令行使用以下命令来对编译类执行增强步骤:

java -cp classpath org.datanucleus.enhancer.DataNucleusEnhancer class-files

classpath 必须包含来自 appengine-java-sdk/lib/tools/ 目录的 JAR datastore-core-*.jardatanucleus-enhancer-*.jarasm-*.jar 和 geronimo-jpa-*.jar(其中 * 是各 JAR 的相应版本号),以及所有数据类。

有关 DataNucleus 字节码增强器的详细信息,请参阅 DataNucleus 文档

获取 EntityManager 实例

应用程序使用 EntityManager 类的实例和 JPA 交互。可通过实例化并调用 EntityManagerFactory 类的实例上的方法来获取此实例。工厂使用 JPA 配置(由名称 "transactions-optional" 标识)来创建 EntityManager 实例。

由于 EntityManagerFactory 实例需要时间来初始化,因此应该尽可能重用单个实例。执行该操作的一个简单方式是创建一个具有静态实例的单独包装器类,如下所示:

EMF.java

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

public final class EMF {
    private static final EntityManagerFactory emfInstance =
        Persistence.createEntityManagerFactory("transactions-optional");

    private EMF() {}

    public static EntityManagerFactory get() {
        return emfInstance;
    }
}

应用程序使用工厂实例来为访问数据存储区的每一请求创建一个 EntityManager 实例。

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import EMF;

// ...
    EntityManager em = EMF.get().createEntityManager();

使用 EntityManager 来存储、更新和删除数据对象并执行数据存储区查询。

完成 EntityManager 实例时,您必须调用其 close() 方法。在调用实例的 close() 方法后使用 EntityManager 实例是错误的。

    try {
        // ... do stuff with em ...
    } finally {
        em.close();
    }

类和字段批注

JPA 保存的每一对象都成为 App Engine 数据存储区中的实体。实体的类型从类的简单名称派生(无包名)。类的每个持久字段代表实体的一个属性,其中属性的名称与字段的名称相同(保留大小写)。

要将 Java 类声明为能够通过 JPA 存储到数据存储区或从数据存储区检索,请为该类指定 @Entity 批注。例如:

import javax.persistence.Entity;

@Entity
public class Employee {
    // ...
}

数据类要存储在数据存储区中的字段必须具有默认为持久的类型或显式声明为持久的类型。您可以在 DataNucleus 网站上找到详述 JPA 默认持久性行为的图表。要显式声明某一字段为持久,通常您将为其提供一个 @Basic 批注,但是目前有阻止这起作用的错误。因此,作为解决办法,您可以使用 @Enumerated 批注。

import java.util.Date;
import javax.persistence.Enumerated;

import com.google.appengine.api.datastore.ShortBlob;

// ...
    @Enumerated
    private ShortBlob data;

字段的类型可以是以下任一类型:

  • 数据存储区支持的核心类型中的一种
  • 核心数据存储区类型的值的 Collection(例如 java.util.List<...>
  • @Entity 类的一个实例或实例集合
  • 一个嵌入类,作为实体上的属性存储

数据类必须具有 public 或 protected 的默认构造函数,以及一个专用于存储对应数据存储区实体的主键的字段。您可以在 4 种不同类型的键字段中选择,每一种都使用不同的值类型和批注。(有关详细信息,请参阅创建数据:键。)最简单的键字段是在对象首次保存到数据存储区时,由 JPA 使用在类的所有其他实例中唯一的值自动填充的长整型值。长整型键使用 @Id 批注,以及@GeneratedValue(strategy = GenerationType.IDENTITY) 批注:

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

// ...
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

以下是一个示例数据类:

import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;

    private String lastName;

    private Date hireDate;

    // Accessors for the fields.  JPA doesn't use these, but your application does.

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    } 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    } 

    public String getLastName() {
        return lastName;
    } 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    } 

    public String getHireDate() {
        return hireDate;
    } 
    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    } 
}

不支持的 JPA 功能

App Engine 实例不支持 JPA 接口的以下功能:

  • 有主的多对多关系,以及无主的关系。虽然 API 中不强制类型检查,但您可以使用显式 Key 值实现无主的关系。
  • “Join”查询。当对父类型执行查询时,不可在过滤条件中使用子实体的字段。请注意,您可以用键直接在查询中测试父实体的关系字段。
  • 聚合查询(group by、having、sum、avg、max、min)
  • 多态查询。您不可执行某一类的查询以获取子类的实例。各类都由数据存储区中的单独实体类型表示。

你可能感兴趣的:(xml,Web,ant,jpa,GAE)