基于Field的持久对象

来源:互联网 发布:高德地图数据采集 编辑:程序博客网 时间:2024/05/16 11:56

Field-based Persistent Objects
基于Field的持久对象

注:本文选自Resin3.0.12所带文档
 
EJB 3.0 supports a field-based relational model: each Java field represents a database column. The tutorial shows the configuration, classes, and client code for a single-table entity.

EJB3.0支持一种基于字段的关系模型:每一个Java字段代表一个数据库列。本教程介绍适用独表实体的配置、类和客户代码。

Overview 概览


EJB 3.0 provides a Java model for a relational database, focusing on solving that single, specific problem. Earlier EJB versions overgeneralized, trying to support non-relational data, and lost focus and clarity. Other persistent object specifications, like JDO, tried to provide transparent persistence for Java objects and tried to support both object and relational databases. By restricting to relational database mapping, EJB 3.0 can provide powerful Java models and still simplify the specification and its use.


EJB 3.0 为关系数据库提供一个Java模型,定位放在解决单一的、特殊的问题。早先的EJB版本功能定位不突出,企图支持非关系型数据,从而丧失了针对性和透明。其他的持久对象规范,像JDO,试图为Java对象提供透明的持久,并试图支持对象数据库和关系数据库。通过限定关系数据库映射,EJB 3.0 可以提供强大的java模型并且它的规范和使用依然简单。

==

A typical project using EJB 3.0 starts planning with the relational database schema and matching the Java model to that schema.This data-driven approach contrasts with a transparent persistent object approach which starts with Java classes and then tries to create storage to match the Java model, an approach more typical of object-oriented databases.While the transparent persistence model may be appropriate for some applications, EJB 3.0 wisely leaves transparent persistence to other products and specifications, and concentrates on the relational database model.


====
一个典型的使用EJB 3.0的项目,开始于编制关系数据库组建方案,然后将java模型与这个组建方案相匹配。这种数据驱动的方法与具有一种透明持久类的方法,即以Java类开始,然后设法创建数据存储来匹配这个Java模型,一种更典型的由对象导向的数据库方法,形成对照。当这种透明的持久模型可能适用某些应用时, EJB 3.0聪明地放弃透明持久转向其他产品和规范,而全神贯注于关系型数据库模型。
====

In a way, EJB 3.0 simply provides an extension to SQL queries, returning fully-populated Java objects instead of just returning primitive values like Strings.

在某种程序上,EJB 3.0仅仅提供一个返回fully-populated Java对象取代仅仅返回像串一样的简单的值的SQL查询的扩展。

在某种程序上,EJB 3.0仅仅提供一个SQL查询扩展,即一个返回全部封装的Java对象取代仅仅返回像串一样的简单的值的SQL查询的扩展,。

That somewhat understates EJB's capabilities since the Java objects are live, updating the database in a object-oriented fashion, and also provides caching. Still, viewing EJB 3.0 as a SQL extension supporting relations and objects is a good starting model.

有点保守地说,EJB的能力 since Java对象是活的,更新一个以对象导向方式的数据库,并且也提供高速缓存。

观察作为一个支持关系和对象的SQL扩展的EJB3.0仍然是一个好的原始模型。

The tutorial uses "entity" to mean a persistent object. In EJB 3.0, an entity is a Java class instance.

教程使用“entity”来表示持久对象。在EJB 3.0中 ,一个实体就是一个Java类的实例。

■Differences with EJB 2.1
与EJB 2.1的差异

The EJB 3.0 draft is primarily a process of removing features superfluous to supporting persistent objects.
EJB 3.0草案首先是一个去掉过量支持持久对象的特征的处理过程

·No home interfaces
·没有home接口

·No local interfaces
·没有local接口

·No instance pooling
·没有实例池

·No special create or remove methods
·没有专门的创建或者移去方法

·No special find or select methods
·没有专门的查找或者选择方法

·Deployment descriptor is optional
·部署描述符是可选的

EJB 3.0 relies on JDK 1.5 annotations to configure entities in a maintainable, self-documenting way.
EJB 3.0依赖JDK 1.5注释符,以一种可维护的自带文档办法来配置实体。


·Only one Java class needed per table (no interface needed)
·每一个表只需要一个Java类(不需要接口)

·Annotation per field
·注释每一个字段

·Annotation directly in Java class
·在Java类中直接注释

·Direct java instance (no proxy or stub needed)
·直接的java实例(没有代理或者存根)

■Files in this tutorial
■在这个教程中的文件

WEB-INF/web.xml  web.xml configuration 
WEB-INF/classes/example/Course.java  The course bean 
WEB-INF/classes/example/CourseServlet.java  The course servlet 


■Database Model
■数据库模型


The tutorial's design begins with its database model. The table is a collection of school courses, each with an assigned teacher. The table has an integer primary key "id" and two string data fields, "course" and "teacher".

教程的设计开始于它的数据模型。表是学校课程的一个集合,每个课程指派一个教师。表有一个整型主键“id”和两个串数据字段,“course”和“teacher”。


course.sql  CREATE TABLE ejb3_basic_courses (
  id INTEGER PRIMARY KEY auto_increment,

  course VARCHAR(250),
  teacher VARCHAR(250)
);

INSERT INTO ejb3_basic_courses VALUES('Potions', 'Severus Snape');
INSERT INTO ejb3_basic_courses VALUES('Transfiguration', 'Minerva McGonagall');

 


To judge the complexity of EJB 3.0, it's useful to compare the EJB Java model to the simplest possible Java model. The simple model has a single class, Course, for the table and three fields for the table's columns.
要评价EJB 3.0的复杂性,将EJB Java 模型与最简单的可能的java模型比较是有用的。简单的模型有一个用于表的单独的类Course,和三个用于表的列的字段。

Minimal Java model  package example;

public class Course {
  private int _id;
  private String _course;
  private String _teacher;
}

The minimal class is missing any description of its intended use as a persistent object, information needed for maintainable code.


In theory, a persistent object tool could use the minimal class automatically, but without more information, the source doesn't properly describe the class behavior.

理论上,一个持久对象工具能够自动地使用最小的类,但没有更多的信息,资源不能完全描述类的行为。

Fortunately, the JDK 1.5 metadata annotations can describe the persistence information in a maintainable, self-documenting way.
幸运的是,JDK 1.5元数据注释能(in a maintainable, self-documenting way)描述持久信息。


Of course, those annotations might have default values and should be overridable by an optional XML configuration file, but it's necessary to annotate the intended function of the entity in the Java source itself to properly document and validate the Java code.

当然,那些注释可能有缺省值,应该通过一个可选择的XML配置文件来overridable,but it's necessary to annotate the intended function of the entity in the Java source itself to properly document and validate the Java code.

Persistent Object Implementation


The minimal Java class needs the following annotations to produce a maintainable persistent object:

A annotation to mark the class as persistent.

An annotation naming the relational table for the class.

An annotation to mark the primary key and any auto-generation capability.

Annotations to mark each persistent field.

Annotations naming the columns for the table.

The following code shows the EJB 3.0 annotations for the course entity. As a quick comparison with the minimal Java class shows, EJB 3.0 is close to the simplest possible implementation of the Java model which provides the necessary annotations in the list.

Course.java

package example;

@javax.ejb.Entity (access=javax.ejb.AccessType.FIELD)

@javax.ejb.Table (name="ejb3_basic_course")

public class Course {

  @javax.ejb.Id (generator=javax.ejb.GeneratorType.AUTO)
  @javax.ejb.Column (name="id")
  private int _id;

  @javax.ejb.Basic
  @javax.ejb.Column (name="course")
  private String _course;

  @javax.ejb.Basic
  @javax.ejb.Column (name="teacher")
  private String _teacher;

  public String course()
  {
    return _course;
  }

  public String teacher()
  {
    return _teacher;
  }
}

 


The example uses the course() and teacher() methods to emphasize that the field accesses to _course and _teacher are live, i.e. they read and write the database values directly. (Under the covers, Resin uses bytecode enhancement to make this work.)
实例使用course()和teacher()方法来强调field存取_course和_teacher是生动的,它们直接读写数据库值。 (Under the covers, Resin uses bytecode enhancement to make this work.)


@Entity - marking the class as persistent
@Entity - 标记类为持久的

Course uses the @Entity to mark the Java class as a field-based persistent object.

@javax.ejb.Entity(access=FIELD)
 


@javax.ejb.Entity declares a Java class as an entity bean.
@javax.ejb.Entity 宣告一个Java类为实体bean.


The access=FIELD value means the bean's fields are persistent, as in JDO. Unlike JDO, only the bean itself or its children may access the fields. Other classes must use the bean's methods, like getters or setters, to indirectly access the fields. The default access value is PROPERTY, meaning method getters are enhanced.

access=FIELD值意味着bean的域是持久的,像在JDO中一样。与JDO不同的是,仅bean自已或者它的孩子可以存取这个域。其他的类必须使用bean的方法,像getters或者setters,来间接地存取域。缺省的存取值是PROPERTY,意味着方法getters是增强的。

@Table - naming the table
@Table - 命名表

@javax.ejb.Table specifies the SQL database table name to be used. If @Table is unspecified, Resin will use the class name as the table name.

@javax.ejb.Table 指定被使用的SQL数据库表名. 如果 @Table 没有被指定,Resin将使用类名作为表名。


@javax.ejb.Table(name="ejb3_basic_course")

 


@Id - marking the primary key
@Id - 标记主键

The @Id attribute marks the bean's primary key. The EntityManager.find method looks up a bean instance with the primary key, and relations use the primary key to link beans together.

@javax.ejb.Id (generator=AUTO)
@javax.ejb.Column (name="id")
private int _id;

 


The optional generator=AUTO specifies automatic generation of primary keys when beans are created. The default NONE does not automatically create primary keys. AUTO generates primary keys depending on the database. Postgres, for example, will use a SEQUENCE, while Resin's built-in database will use an auto_increment IDENTITY.

generator=AUTO 的选项,特指当bean被创建时自动地生成主键。缺省值NONE不自动地创建主键。AUTO 生成主键依赖数据库。例如,Postgres,将使用SEQUENCE,当Resin的built-in 数据库时,将使用一个自动增量 IDENTITY.


The optional @Column annotation specifies the SQL column name. The default SQL column for an @Id is "ID".

@Basic - marking a persistent field
The @Basic attribute marks a basic data column like a string or integer or double.

@javax.ejb.Basic
@javax.ejb.Column (name="course")
private String _course;

 


@Column - naming the column
The optional @Column annotation specifies SQL column name. For an @Id, the default column name is "ID". For a @Basic field, the default column name is the field name.

Under the covers: bytecode enhancement
Resin processes the bean's class to implement field-enhancement. In practice, this means replacing setting a field with a Resin setter and getting a field with a Resin getter.

public String course()
{
  return _course;
}

 


For example, Resin would process the above method and produce something like:

public String course()
{
  return __caucho_get_course();
}

 


Client Servlet


The client servlet queries the database for all courses and lists them. It uses the EntityManager API to create a Query and uses the Query to obtain the results.

CourseServlet.java

public class CourseServlet extends HttpServlet {
  private EntityManager _manager;

  public void setEntityManager(EntityManager manager)
  {
    _manager = manager;
  }

  public void service(HttpServletRequest req, HttpServletResponse res)
    throws java.io.IOException, ServletException
  {
    PrintWriter out = res.getWriter();

    res.setContentType("text/html");

    out.println("<h3>Course Details</h3>");

    Query query = _manager.createQuery("SELECT o FROM Course o");
   
    for (Course course : (List<Course>) query.listResults()) {
      out.println("course: " + course.course() + "<br>");
      out.println("teacher: " + course.teacher() + "<br>");
      out.println("<br>");
    }
  }
}

 


Course Details
course: Potions
instructor: Severus Snape

course: Transfiguration
instructor: Minerva McGonagall

 


EntityManager
EntityManager is the primary interface for finding, querying, adding and deleting persistent beans. It is stored in JNDI at java:comp/EntityManager.

public void setEntityManager(EntityManager manager)
{
  _manager = manager;
}

 


The example uses dependency injection to configure the entity manager. The web.xml will find the EntityManager in JNDI and set it in the servlet before calling the init()

web.xml configuration

<servlet servlet-name="basic" servlet-class="example.CourseServlet">
  <init entity-manager="${jndi:lookup('java:comp/EntityManager')}"/>
</servlet>

 


Of course, a servlet can also use JNDI directly in its init() method.

Query
Query acts like a PreparedStatement in JDBC. It saves a parsed SQL query and allows for parameters.

Query query = _manager.createQuery("SELECT o FROM Course o");

 


The SQL used for EJB 3.0 is an enhanced database SQL. The query can return objects directly ("SELECT o") and it can traverse relations ("o.next.data"). In most other respects, it can be thought of as regular SQL.

List list = query.listResults();

 


The query returns its values with listResults(). Queries which return a single value can use getSingleResult().

query用listResults()返回它的值。返回一个单独值的查询可能使用getSingleResult()。

Resin Configuration


The Resin configuration is fairly straightforward. Resin needs to start the ejb-server, configure the JDBC data-source, and list the beans that will be used.

WEB-INF/web.xml

<web-app>
  <!-- server configuration -->
  <ejb-server data-source="jdbc/resin">
    <bean type="example.Course"/>
  </ejb-server>

  <servlet servlet-name="basic" servlet-class="example.CourseServlet">
    <init entity-manager="${jndi:lookup('java:comp/EntityManager')}"/>
  </servlet>

  <servlet-mapping url-pattern="/basic" servlet-name="basic"/>
</web-app>

 


The <ejb-server> configures Resin's EJB support. Each <bean> adds a new bean (entity, session or message-driven.)

The servlet's <init> method uses dependency injection to configure the servlet. Some applications may want to call JNDI directly from within the servlet, although that removes some configuration flexibility.