37 * NOTE: As the entity manager is injected by the container, it is 38 * often a proxy. Hence the return value is the class name of the 39 * delegate of the actual injected instance 40 */ 41 public String getProvider() { 42 return em.getDelegate().getClass().getName(); 43 } 44 45 public Message log(String message) { 46 Message result = new Message(message); 47 em.persist(result); 48 return result; 49 } 50 51 }
这个会话bean本身也有不明确的地方。它使用了JPA,但没有声明将要使用哪一个特定的持久性提供者(事实上,定义一个工业标准的持久性API的主要目的之一是为了能够从一个提供者切换到另一个)。
这个bean并未直接与一个 JPA提供者建立连接,而是依靠容器新获得的功能(即,从JEE 5以来)在需要时注入JPA连接。另外,有个好消息是Weblogic Server 10.0是第一个兼容JEE 5的应用服务器。
容器能够以两种形式向会话Bean注入JPA依赖关系:@PersistenceUnit或@PersistenceContext注释。我们所使用的是@PersistenceContext(JPAServiceBean.java的第 30和31行)。
如果让我将它与JDBC进行粗略的类比,那么@PersistenceUnit相当于一个DataSource,而@PersistenceContext则相当于一个Connection。在JPA术语当中,这一对概念是由JPA定义的接口EntityManagerFactory和EntityManager分别实现的。
通过这些接口和少数其他的方式(例如,Query),JPA已经定义了一个比传统的JDBC通过SQL提供的方式更高层的面向对象抽象与数据库进行交互。通过JPA,您可以借助面向对象视图与底层数据库进行交互。应用程序可以通过 EntityManager接口中的方法创建、更新、查询和删除对象——JPA提供者与应用程序协同工作截听这些对象级的改变并且适当地将它们与相应的INSERT、UPDATE、SELECT和DELETE数据库操作映射起来。
这个基本的JPA应用程序已经完成,下面是持久性类。
Message.java
01 package service;
02
03 import java.io.Serializable;
04 import java.util.Date;
05
06 import javax.persistence.*;
07
08 /**
09 * A simple persistent message. The entity is declared to be serializable to
10 * pass across processes.
11 *
12 * The message is assigned an identifier by the persistence provider.
13 * A timestamp is also set to the message when it is constructed.
14 *
15 * Annotates the fields with their persistent properties.
16 *
17 * @author ppoddar
18 *
19 */
20 @SuppressWarnings("serial")
21 @Entity
22 public class Message implements Serializable {
23 /**
24 * Annotates the field as primary identity for this instance. Also the
25 * persistence provider will generate the identity value. That is why
26 * there is no corresponding setter method.
27 */
28 @Id
29 @GeneratedValue
30 private long id;
31
32 /**
33 * Annotates the field to carry a TIMESTAMP value in the database column.
34 * The column name is different than the default value of
timestamp
35 * because many databases will reserve that word.
36 *
37 * The field is immutable by application (no setter method) and set on
38 * construction with current time.
39 */
40 @Temporal(TemporalType.TIMESTAMP)
41 @Column(name="createdOn")
42 private Date timestamp;
43
44 /**
45 * Does not annotate but the field will be persisted nevertheless by
46 * convention of String and primitive types being persistent by default.
47 */
48 private String body;
49
50 protected Message() {
51 this("");
52 }
53
54 public Message(String body) {
55 timestamp = new Date();
56 this.body = (body == null) ? "" : body;
57 }
58
59 public long getId() {
60 return id;
61 }
62
63 public String getBody() {
64 return body;
65 }
66
67 public Date getTimestamp() {
68 return timestamp;
69 }
70 }