- 浏览: 147430 次
- 来自: ...
文章分类
最新评论
-
fisher:
真心感谢楼主! 解决了困扰我几天的大问题啊!
EntityManagerFactory -
悲剧了:
太棒了,我们项目正在用这个
struts2 convention-plugin -
nforce_com:
...
jpa继承关系详解 -
guanchuangsheng:
精辟~~
总算明白了·~
桥接模式和适配器模式的区别 -
lping2:
强,写得太全面了
EntityManagerFactory
1 Overview
Apache OpenJPA是JPA规范的一个实现,它既可以用于POJO的持久层,也可以被集成到EJB3.0兼容的容器中或者其它轻量级的框架中。在Apache Geronimo 2.0 版本中通过OpenEJB使用了OpenJPA。在WebLogic和WebShpere中也采用了OpenJPA。目前OpenJPA的最新版本是1.0.2。在OpenJPA中大量使用了generic和annotation,因此需要使用1.5以上版本的JDK。
以下是JPA中使用的主要组件:
Persistence: javax.persistence.Persistence类包含静态方法用于获得EntityManagerFactory对象。
EntityManagerFactory: javax.persistence.EntityManagerFactory类是创建EntityManager的工厂类。
EntityManager: javax.persistence.EntityManager是应用中主要使用的接口,它主要用于管理持久对象,也用于创建Query 接口。
Entity。Entity用于封装持久对象。
EntityTransaction: EntityTransaction 用于封装事务,javax.persistence.EntityTransaction和EntityManager之间是一对一的关系。
Query: javax.persistence.Query接口用于持久对象的查询。它支持Java Persistence Query Language (JPQL) 和 Structured Query Language (SQL)。
PersistenceException: JPA异常体系的根是PersistenceException,它继承于RuntimeException。OpenJPA中抛出的异常都实现了org.apache.openjpa.util.ExceptionInfo接口,用于提供额外的信息。
以下是使用JPA的一个例子:
Java代码
EntityManagerFactory factory = Persistence.createEntityManagerFactory(null);
EntityManager em = factory.createEntityManager(PersistenceContextType.EXTENDED);
EntityTransaction tx = em.getTransaction();
tx.begin();
Query query = em.createQuery("select e from Employee e where e.division.name = 'Research' AND e.avgHours > 40");
List results = query.getResultList ();
for (Object res : results) {
Employee emp = (Employee) res;
emp.setSalary(emp.getSalary() * 1.1);
}
tx.commit();
em.close();
factory.close();
EntityManagerFactory factory = Persistence.createEntityManagerFactory(null);
EntityManager em = factory.createEntityManager(PersistenceContextType.EXTENDED);
EntityTransaction tx = em.getTransaction();
tx.begin();
Query query = em.createQuery("select e from Employee e where e.division.name = 'Research' AND e.avgHours > 40");
List results = query.getResultList ();
for (Object res : results) {
Employee emp = (Employee) res;
emp.setSalary(emp.getSalary() * 1.1);
}
tx.commit();
em.close();
factory.close();
2 Entity
JPA 区分两种不同的persistent class: entity classes 和 embeddable classes. EntityManager可以通过persistent identity来查询entity 实例,或者在Query中指定条件来查询entity实例。在另一方面,embedded实例没有persistent identity,也不能直接从EntityManager或者Query的查询中得到。
2.1 Restrictions on Persistent Classes
在编写persistent class的时候,不需要继承任何父类或者实现任何接口。 但是persistent class需要一个无参构造函数。如果需要的话,OpenJPA的enhancer也可以创建一个protected 无参构造函数,所以当使用enhancer的时候,persistent class可以不提供无参构造函数。OpenJPA支持final classes 和 final methods。
所有的entity classes必须提供一个或者多个字段来组成一个persistent identity。你可以为persistent class提供一个version字段,用来检测并发修改,这个字段必须是整数型的(例如int,Long)或者是java.sql.Timestamp。version字段应该是不可变(immutable)的。除了version字段以外,OpenJPA也支持通过其它的方式检测并发修改。
JPA支持persistent class的继承,但是persistent class不能继承自一些包含native实现的系统类,例如:java.net.Socket 和 java.lang.Thread。如果一个persistent class继承自non-persistent class,那么non-persistent class中的字段不能被持久化。具有继承关系的所有类必须有相同的identity type。
2.2 Entity Identity
Java中有两种判断object identity的方式:使用==操作符判断同一个JVM中两个引用的值是否相等,或者说指向相同对象;使用equals 方法来判断两个对象是否满足定制的相等条件。JPA中引入了另外一种判断object identity的方式,称为entity identity或者 persistent identity。Entity identity被封装到持久对象的identity字段中,如果两个相同类型的entities拥有相同的identity字段,那么这两个entities代表datastore中相同的状态。Identity字段必须是以下类型:primitives、primitive wrappers、 Strings、Dates、Timestamps或者embeddable types。
当你处理single persistence context的时候,可以不必通过比较identity字段来判断这些entities是否代表datastore中相同的状态,而是可以通过==操作符。JPA要求每一个persistence context中只能保持一个object来代表每一个datastore record,因此entity identity相当于引用相等。
2.2.1 Identity Class
如果entity 中只有一个identity字段,那么可以将这个字段用作所有EntityManager APIs的identity object;否则必须提供一个identity class,它必须符合以下条件:
The class must be public.
The class must be serializable.
The class must have a public no-args constructor.
The names of the non-static fields or properties of the class must be the same as the names of the identity fields or properties of the corresponding entity class, and the types must be identical.
The equals and hashCode methods of the class must use the values of all fields or properties corresponding to identity fields or properties in the entity class.
If the class is an inner class, it must be static.
All entity classes related by inheritance must use the same identity class, or else each entity class must have its own identity class whose inheritance hierarchy mirrors the inheritance hierarchy of the owning entity classes.
以下是个使用多个identity字段的entity class的例子:
Java代码
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public static class MagazineId {
// each identity field in the Magazine class must have a
// corresponding field in the identity class
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
/**
* Equality must be implemented in terms of identity field
* equality, and must use instanceof rather than comparing
* classes directly (some JPA implementations may subclass the
* identity class).
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof MagazineId)) {
return false;
}
MagazineId rhs = (MagazineId)obj;
boolean b1 = (isbn == rhs.isbn || (isbn != null && isbn.equals(rhs.isbn)));
boolean b2 = (title == rhs.title || (title != null && title.equals(rhs.title)));
return b1 && b2;
}
/**
* Hashcode must also depend on identity values.
*/
public int hashCode(){
int h1 = (isbn == null ? 0 : isbn.hashCode());
int h2 = (title == null ? 0 : title.hashCode());
return h1 ^ h2;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
}
}
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public static class MagazineId {
// each identity field in the Magazine class must have a
// corresponding field in the identity class
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
/**
* Equality must be implemented in terms of identity field
* equality, and must use instanceof rather than comparing
* classes directly (some JPA implementations may subclass the
* identity class).
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof MagazineId)) {
return false;
}
MagazineId rhs = (MagazineId)obj;
boolean b1 = (isbn == rhs.isbn || (isbn != null && isbn.equals(rhs.isbn)));
boolean b2 = (title == rhs.title || (title != null && title.equals(rhs.title)));
return b1 && b2;
}
/**
* Hashcode must also depend on identity values.
*/
public int hashCode(){
int h1 = (isbn == null ? 0 : isbn.hashCode());
int h2 = (title == null ? 0 : title.hashCode());
return h1 ^ h2;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
}
}
除了手工编写Id class之外,也可以通过ApplicationIdTool自动生成Id class,例如:
java org.apache.openjpa.enhance.ApplicationIdTool -s Id Magazine.java
关于其可选的命令行参数,请参考Apache OpenJPA的user guide。
如果觉得在命令行上执行命令比较麻烦,也可以在程序里直接调用其main方法,如下:
Java代码
String suffix = "Id";
String java = "./src/com/example/entity/Product.java";
ApplicationIdTool.main(new String[]{"-d", "./src/", "-s", suffix, java});
String suffix = "Id";
String java = "./src/com/example/entity/Product.java";
ApplicationIdTool.main(new String[]{"-d", "./src/", "-s", suffix, java}); 关于如何在类的继承体系中编写identity class,请参考Apache OpenJPA的user guide。
2.3 Lifecycle Callbacks
经常需要在persistent object 生命周期的不同阶段实施不用的动作。JPA包含了多种不同的callback 方法来监控persistent object。这些callback方法可以在persistent classes 中定义,也可以在non-persistent listener classes 中定义。
2.3.1 Callback Methods
每一个persistence event都有相关的callback方法标记,如下:
PrePersist: 用这个annotation 标记的方法会在对象被持久化之前调用。这个方法可以用来为持久化对象设置主键。
PostPersist: 用这个annotation 标记的方法会在对象被持久化之后调用。这个方法可以用来在model被保存后更新view。
PostLoad: 用这个annotation 标记的方法会在对象中所有eagerly fetched 字段被加载后调用。这个方法通常用来根据加载后的持久化字段的值更初始化非持久字段的值。
PreUpdate: 用这个annotation 标记的方法会在对象中持久字段的值被flush到datastore前被调用。 这个方法通常用来根据非持久字段的值来设置持久字段。
PostUpdate: 用这个annotation 标记的方法会在对象中持久字段值的改变被保存到datastore后调用。这个方法可以用来清空应用层的过期数据。
PreRemove: 用这个annotation 标记的方法会在对象经事务标记成已删除状态前调用。在这个方法中访问持久字段是合法的。在这个方法中,可以基于复杂的条件级联删除其它对象,或者做其它的清理工作。
PostRemove: 用这个annotation 标记的方法会在对象被标记成已删除状态后调用。
除了属性存取方法外,任何没有参数的方法都可以用以上annotation标记。一个方法也可以使用多个annotation标记。以下是个persistent classes的例子
Java代码
/**
* Example persistent class declaring our entity listener.
*/
@Entity
public class Magazine {
@Transient
private byte[][] data;
@ManyToMany
private List<Photo> photos;
@PostLoad
public void convertPhotos() {
data = new byte[photos.size()][];
for (int i = 0; i < photos.size(); i++)
data[i] = photos.get(i).toByteArray();
}
@PreDelete
public void logMagazineDeletion() {
getLog().debug("deleting magazine containing" + photos.size()
+ " photos.");
}
}
/**
* Example persistent class declaring our entity listener.
*/
@Entity
public class Magazine {
@Transient
private byte[][] data;
@ManyToMany
private List<Photo> photos;
@PostLoad
public void convertPhotos() {
data = new byte[photos.size()][];
for (int i = 0; i < photos.size(); i++)
data[i] = photos.get(i).toByteArray();
}
@PreDelete
public void logMagazineDeletion() {
getLog().debug("deleting magazine containing" + photos.size()
+ " photos.");
}
} 也可以使用XML文件,如下:
Xml代码
<entity class="Magazine">
<pre-remove>logMagazineDeletion</pre-remove>
<post-load>convertPhotos</post-load>
</entity>
<entity class="Magazine">
<pre-remove>logMagazineDeletion</pre-remove>
<post-load>convertPhotos</post-load>
</entity>
2.3.2 Entity Listeners
在persistent classes 中加入Lifecycle Callbacks并不总是理想,更优雅的方式是在 non-persistent listener class 中处理生命周期内的相关事件。Entity listener classes需要有一个无参的构造函数,callback 方法需要有个java.lang.Object 型的参数来指定激发事件的持久对象。Entities可以通过EntityListeners这个annotation来枚举listeners。以下是个Entity和Entity Listener的例子:
Java代码
/**
* Example persistent class declaring our entity listener.
*/
@Entity
@EntityListeners({ MagazineLogger.class, ... })
public class Magazine {
// ... //
}
/**
* Example entity listener.
*/
public class MagazineLogger {
@PostPersist
public void logAddition(Object pc) {
getLog ().debug ("Added new magazine:" + ((Magazine) pc).getTitle ());
}
@PreRemove
public void logDeletion(Object pc) {
getLog().debug("Removing from circulation:" +
((Magazine) pc).getTitle());
}
}
/**
* Example persistent class declaring our entity listener.
*/
@Entity
@EntityListeners({ MagazineLogger.class, ... })
public class Magazine {
// ... //
}
/**
* Example entity listener.
*/
public class MagazineLogger {
@PostPersist
public void logAddition(Object pc) {
getLog ().debug ("Added new magazine:" + ((Magazine) pc).getTitle ());
}
@PreRemove
public void logDeletion(Object pc) {
getLog().debug("Removing from circulation:" +
((Magazine) pc).getTitle());
}
} 也可以在XML文件中定义Entity Listeners,如下:
Xml代码
<entity class="Magazine">
<entity-listeners>
<entity-listener class="MagazineLogger">
<post-persist>logAddition</post-persist>
<pre-remove>logDeletion</pre-remove>
</entity-listener>
</entity-listeners>
</entity>
<entity class="Magazine">
<entity-listeners>
<entity-listener class="MagazineLogger">
<post-persist>logAddition</post-persist>
<pre-remove>logDeletion</pre-remove>
</entity-listener>
</entity-listeners>
</entity> 关于entity listeners的调用顺序,默认listener会最先被调用;接下来,父类的listeners会先调用,然后是子类的listeners;最后,如果entity上还有某个事件的多个callback方法,那么会按照这些callback方法在entity上声明顺序来调用。
可以使用以下两个class-level的annotation,以便在entity listeners的调用链上去掉默认listener和父类中定义的listener:
ExcludeDefaultListeners: 这个annotation 表明这个类及其子类上不再调用默认listeners。
ExcludeSuperclassListeners: 这个annotation 指示OpenJPA不调用父类上声明的任何entity listeners。
Apache OpenJPA是JPA规范的一个实现,它既可以用于POJO的持久层,也可以被集成到EJB3.0兼容的容器中或者其它轻量级的框架中。在Apache Geronimo 2.0 版本中通过OpenEJB使用了OpenJPA。在WebLogic和WebShpere中也采用了OpenJPA。目前OpenJPA的最新版本是1.0.2。在OpenJPA中大量使用了generic和annotation,因此需要使用1.5以上版本的JDK。
以下是JPA中使用的主要组件:
Persistence: javax.persistence.Persistence类包含静态方法用于获得EntityManagerFactory对象。
EntityManagerFactory: javax.persistence.EntityManagerFactory类是创建EntityManager的工厂类。
EntityManager: javax.persistence.EntityManager是应用中主要使用的接口,它主要用于管理持久对象,也用于创建Query 接口。
Entity。Entity用于封装持久对象。
EntityTransaction: EntityTransaction 用于封装事务,javax.persistence.EntityTransaction和EntityManager之间是一对一的关系。
Query: javax.persistence.Query接口用于持久对象的查询。它支持Java Persistence Query Language (JPQL) 和 Structured Query Language (SQL)。
PersistenceException: JPA异常体系的根是PersistenceException,它继承于RuntimeException。OpenJPA中抛出的异常都实现了org.apache.openjpa.util.ExceptionInfo接口,用于提供额外的信息。
以下是使用JPA的一个例子:
Java代码
EntityManagerFactory factory = Persistence.createEntityManagerFactory(null);
EntityManager em = factory.createEntityManager(PersistenceContextType.EXTENDED);
EntityTransaction tx = em.getTransaction();
tx.begin();
Query query = em.createQuery("select e from Employee e where e.division.name = 'Research' AND e.avgHours > 40");
List results = query.getResultList ();
for (Object res : results) {
Employee emp = (Employee) res;
emp.setSalary(emp.getSalary() * 1.1);
}
tx.commit();
em.close();
factory.close();
EntityManagerFactory factory = Persistence.createEntityManagerFactory(null);
EntityManager em = factory.createEntityManager(PersistenceContextType.EXTENDED);
EntityTransaction tx = em.getTransaction();
tx.begin();
Query query = em.createQuery("select e from Employee e where e.division.name = 'Research' AND e.avgHours > 40");
List results = query.getResultList ();
for (Object res : results) {
Employee emp = (Employee) res;
emp.setSalary(emp.getSalary() * 1.1);
}
tx.commit();
em.close();
factory.close();
2 Entity
JPA 区分两种不同的persistent class: entity classes 和 embeddable classes. EntityManager可以通过persistent identity来查询entity 实例,或者在Query中指定条件来查询entity实例。在另一方面,embedded实例没有persistent identity,也不能直接从EntityManager或者Query的查询中得到。
2.1 Restrictions on Persistent Classes
在编写persistent class的时候,不需要继承任何父类或者实现任何接口。 但是persistent class需要一个无参构造函数。如果需要的话,OpenJPA的enhancer也可以创建一个protected 无参构造函数,所以当使用enhancer的时候,persistent class可以不提供无参构造函数。OpenJPA支持final classes 和 final methods。
所有的entity classes必须提供一个或者多个字段来组成一个persistent identity。你可以为persistent class提供一个version字段,用来检测并发修改,这个字段必须是整数型的(例如int,Long)或者是java.sql.Timestamp。version字段应该是不可变(immutable)的。除了version字段以外,OpenJPA也支持通过其它的方式检测并发修改。
JPA支持persistent class的继承,但是persistent class不能继承自一些包含native实现的系统类,例如:java.net.Socket 和 java.lang.Thread。如果一个persistent class继承自non-persistent class,那么non-persistent class中的字段不能被持久化。具有继承关系的所有类必须有相同的identity type。
2.2 Entity Identity
Java中有两种判断object identity的方式:使用==操作符判断同一个JVM中两个引用的值是否相等,或者说指向相同对象;使用equals 方法来判断两个对象是否满足定制的相等条件。JPA中引入了另外一种判断object identity的方式,称为entity identity或者 persistent identity。Entity identity被封装到持久对象的identity字段中,如果两个相同类型的entities拥有相同的identity字段,那么这两个entities代表datastore中相同的状态。Identity字段必须是以下类型:primitives、primitive wrappers、 Strings、Dates、Timestamps或者embeddable types。
当你处理single persistence context的时候,可以不必通过比较identity字段来判断这些entities是否代表datastore中相同的状态,而是可以通过==操作符。JPA要求每一个persistence context中只能保持一个object来代表每一个datastore record,因此entity identity相当于引用相等。
2.2.1 Identity Class
如果entity 中只有一个identity字段,那么可以将这个字段用作所有EntityManager APIs的identity object;否则必须提供一个identity class,它必须符合以下条件:
The class must be public.
The class must be serializable.
The class must have a public no-args constructor.
The names of the non-static fields or properties of the class must be the same as the names of the identity fields or properties of the corresponding entity class, and the types must be identical.
The equals and hashCode methods of the class must use the values of all fields or properties corresponding to identity fields or properties in the entity class.
If the class is an inner class, it must be static.
All entity classes related by inheritance must use the same identity class, or else each entity class must have its own identity class whose inheritance hierarchy mirrors the inheritance hierarchy of the owning entity classes.
以下是个使用多个identity字段的entity class的例子:
Java代码
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public static class MagazineId {
// each identity field in the Magazine class must have a
// corresponding field in the identity class
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
/**
* Equality must be implemented in terms of identity field
* equality, and must use instanceof rather than comparing
* classes directly (some JPA implementations may subclass the
* identity class).
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof MagazineId)) {
return false;
}
MagazineId rhs = (MagazineId)obj;
boolean b1 = (isbn == rhs.isbn || (isbn != null && isbn.equals(rhs.isbn)));
boolean b2 = (title == rhs.title || (title != null && title.equals(rhs.title)));
return b1 && b2;
}
/**
* Hashcode must also depend on identity values.
*/
public int hashCode(){
int h1 = (isbn == null ? 0 : isbn.hashCode());
int h2 = (title == null ? 0 : title.hashCode());
return h1 ^ h2;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
}
}
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public static class MagazineId {
// each identity field in the Magazine class must have a
// corresponding field in the identity class
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
/**
* Equality must be implemented in terms of identity field
* equality, and must use instanceof rather than comparing
* classes directly (some JPA implementations may subclass the
* identity class).
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof MagazineId)) {
return false;
}
MagazineId rhs = (MagazineId)obj;
boolean b1 = (isbn == rhs.isbn || (isbn != null && isbn.equals(rhs.isbn)));
boolean b2 = (title == rhs.title || (title != null && title.equals(rhs.title)));
return b1 && b2;
}
/**
* Hashcode must also depend on identity values.
*/
public int hashCode(){
int h1 = (isbn == null ? 0 : isbn.hashCode());
int h2 = (title == null ? 0 : title.hashCode());
return h1 ^ h2;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("isbn: " + isbn);
sb.append(", title: " + title);
return sb.toString();
}
}
}
除了手工编写Id class之外,也可以通过ApplicationIdTool自动生成Id class,例如:
java org.apache.openjpa.enhance.ApplicationIdTool -s Id Magazine.java
关于其可选的命令行参数,请参考Apache OpenJPA的user guide。
如果觉得在命令行上执行命令比较麻烦,也可以在程序里直接调用其main方法,如下:
Java代码
String suffix = "Id";
String java = "./src/com/example/entity/Product.java";
ApplicationIdTool.main(new String[]{"-d", "./src/", "-s", suffix, java});
String suffix = "Id";
String java = "./src/com/example/entity/Product.java";
ApplicationIdTool.main(new String[]{"-d", "./src/", "-s", suffix, java}); 关于如何在类的继承体系中编写identity class,请参考Apache OpenJPA的user guide。
2.3 Lifecycle Callbacks
经常需要在persistent object 生命周期的不同阶段实施不用的动作。JPA包含了多种不同的callback 方法来监控persistent object。这些callback方法可以在persistent classes 中定义,也可以在non-persistent listener classes 中定义。
2.3.1 Callback Methods
每一个persistence event都有相关的callback方法标记,如下:
PrePersist: 用这个annotation 标记的方法会在对象被持久化之前调用。这个方法可以用来为持久化对象设置主键。
PostPersist: 用这个annotation 标记的方法会在对象被持久化之后调用。这个方法可以用来在model被保存后更新view。
PostLoad: 用这个annotation 标记的方法会在对象中所有eagerly fetched 字段被加载后调用。这个方法通常用来根据加载后的持久化字段的值更初始化非持久字段的值。
PreUpdate: 用这个annotation 标记的方法会在对象中持久字段的值被flush到datastore前被调用。 这个方法通常用来根据非持久字段的值来设置持久字段。
PostUpdate: 用这个annotation 标记的方法会在对象中持久字段值的改变被保存到datastore后调用。这个方法可以用来清空应用层的过期数据。
PreRemove: 用这个annotation 标记的方法会在对象经事务标记成已删除状态前调用。在这个方法中访问持久字段是合法的。在这个方法中,可以基于复杂的条件级联删除其它对象,或者做其它的清理工作。
PostRemove: 用这个annotation 标记的方法会在对象被标记成已删除状态后调用。
除了属性存取方法外,任何没有参数的方法都可以用以上annotation标记。一个方法也可以使用多个annotation标记。以下是个persistent classes的例子
Java代码
/**
* Example persistent class declaring our entity listener.
*/
@Entity
public class Magazine {
@Transient
private byte[][] data;
@ManyToMany
private List<Photo> photos;
@PostLoad
public void convertPhotos() {
data = new byte[photos.size()][];
for (int i = 0; i < photos.size(); i++)
data[i] = photos.get(i).toByteArray();
}
@PreDelete
public void logMagazineDeletion() {
getLog().debug("deleting magazine containing" + photos.size()
+ " photos.");
}
}
/**
* Example persistent class declaring our entity listener.
*/
@Entity
public class Magazine {
@Transient
private byte[][] data;
@ManyToMany
private List<Photo> photos;
@PostLoad
public void convertPhotos() {
data = new byte[photos.size()][];
for (int i = 0; i < photos.size(); i++)
data[i] = photos.get(i).toByteArray();
}
@PreDelete
public void logMagazineDeletion() {
getLog().debug("deleting magazine containing" + photos.size()
+ " photos.");
}
} 也可以使用XML文件,如下:
Xml代码
<entity class="Magazine">
<pre-remove>logMagazineDeletion</pre-remove>
<post-load>convertPhotos</post-load>
</entity>
<entity class="Magazine">
<pre-remove>logMagazineDeletion</pre-remove>
<post-load>convertPhotos</post-load>
</entity>
2.3.2 Entity Listeners
在persistent classes 中加入Lifecycle Callbacks并不总是理想,更优雅的方式是在 non-persistent listener class 中处理生命周期内的相关事件。Entity listener classes需要有一个无参的构造函数,callback 方法需要有个java.lang.Object 型的参数来指定激发事件的持久对象。Entities可以通过EntityListeners这个annotation来枚举listeners。以下是个Entity和Entity Listener的例子:
Java代码
/**
* Example persistent class declaring our entity listener.
*/
@Entity
@EntityListeners({ MagazineLogger.class, ... })
public class Magazine {
// ... //
}
/**
* Example entity listener.
*/
public class MagazineLogger {
@PostPersist
public void logAddition(Object pc) {
getLog ().debug ("Added new magazine:" + ((Magazine) pc).getTitle ());
}
@PreRemove
public void logDeletion(Object pc) {
getLog().debug("Removing from circulation:" +
((Magazine) pc).getTitle());
}
}
/**
* Example persistent class declaring our entity listener.
*/
@Entity
@EntityListeners({ MagazineLogger.class, ... })
public class Magazine {
// ... //
}
/**
* Example entity listener.
*/
public class MagazineLogger {
@PostPersist
public void logAddition(Object pc) {
getLog ().debug ("Added new magazine:" + ((Magazine) pc).getTitle ());
}
@PreRemove
public void logDeletion(Object pc) {
getLog().debug("Removing from circulation:" +
((Magazine) pc).getTitle());
}
} 也可以在XML文件中定义Entity Listeners,如下:
Xml代码
<entity class="Magazine">
<entity-listeners>
<entity-listener class="MagazineLogger">
<post-persist>logAddition</post-persist>
<pre-remove>logDeletion</pre-remove>
</entity-listener>
</entity-listeners>
</entity>
<entity class="Magazine">
<entity-listeners>
<entity-listener class="MagazineLogger">
<post-persist>logAddition</post-persist>
<pre-remove>logDeletion</pre-remove>
</entity-listener>
</entity-listeners>
</entity> 关于entity listeners的调用顺序,默认listener会最先被调用;接下来,父类的listeners会先调用,然后是子类的listeners;最后,如果entity上还有某个事件的多个callback方法,那么会按照这些callback方法在entity上声明顺序来调用。
可以使用以下两个class-level的annotation,以便在entity listeners的调用链上去掉默认listener和父类中定义的listener:
ExcludeDefaultListeners: 这个annotation 表明这个类及其子类上不再调用默认listeners。
ExcludeSuperclassListeners: 这个annotation 指示OpenJPA不调用父类上声明的任何entity listeners。
发表评论
-
EJB3 QL查询
2008-07-17 15:57 1547EJB3 QL查询 EJB3的查询语言是一种和SQL非常类似的 ... -
Table
2008-07-08 12:18 2022Table Table用来定义entity主表的name,ca ... -
Metadata
2008-07-07 19:32 13443 Metadata 通过javax.p ... -
EntityManagerFactory
2008-07-07 19:30 95564 EntityManagerFactory 4.1 Over ... -
Miscellaneous Features
2008-07-07 19:29 134210 Miscellaneous Features 10.1 ... -
Object Locking
2008-07-07 19:27 13508 Object Locking 8.1 Configurin ... -
Query
2008-07-07 19:26 15956 Query 6.1 JPQL Queries 6.1.1Q ... -
jpa继承关系详解
2008-07-07 19:07 82327 Inheritance 对象使用引用以便关联到其它 ... -
JNDI简介
2008-05-29 17:03 1709JNDI简介 & 简单示例 ... -
ejb2 和 ejb3的区别
2008-03-31 13:39 4248EJB 3 和EJB 2.1 的区别 从整个EJB 规范的 ...
相关推荐
标题中的"overview_20200306_V4_overview_氛围灯_vbaexcel_"暗示了这是一个关于2020年3月6日版本的车内氛围灯系统概述,利用VBA(Visual Basic for Applications)和Excel进行自动化管理的项目。这个系统可能是为了...
《SAML V2.0 Technical Overview》(委员会草案02版)是一份由OASIS(组织为开放标准)安全服务技术委员会(Security Services TC)发布的文档,该文档详细介绍了SAML 2.0的技术框架与应用范围。SAML 2.0(Security ...
for MTL in Deep Learning, gives an overview of the literature, and discusses recent advances. In particular, it seeks to help ML practitioners apply MTL by shedding light on how MTL works and ...
"SAP 中文版Overview" 在这个 SAP 中文版Overview 中,我们将详细介绍 SAP 的概念、结构、模块、导航和业务流程等知识点。 MRP、MRPII 和 ERP 的概念 MRP(Material Requirements Planning,物料需求规划)是根据...
OPC Overview This document serves as an overview to OPC. It gives background information, motivation, architectural highlights and an abstract for each OPC topic. Specific interface specifications to ...
这篇名为“Deep Learning in Neural Networks: An Overview”的论文为读者提供了一个全面且深入的深度学习概述,作者们详细介绍了该领域的基本概念、模型以及最新进展。 首先,深度学习的核心在于神经网络。神经...
标题“Palladium Z1 Overview Introduction”和描述“大规模芯片验证加速器介绍”直接指向了文档的主题,即关于Palladium Z1的概述和介绍。Palladium Z1是Cadence公司推出的一款用于大规模芯片验证的加速器产品,它...
Activity概览屏幕(Overview Screen)在Android开发中扮演着重要的角色,它通常被用来展示应用中的最近使用或重要任务,让用户能够快速切换到之前的工作状态。在这个特定的demo代码中,我们将深入探讨如何在Android ...
标题中的“cpu_prometheusd&MySQL_Overview”表明这是一个关于CPU监控与Prometheus与MySQL数据库概览的主题。Prometheus是一款强大的开源系统监控和警报工具,而MySQL则是一种广泛使用的开源关系型数据库管理系统。...
JEDEC JESD15-1.01-2023 COMPACT THERMAL MODEL OVERVIEW JEDEC(Joint Electron Device Engineering Council,联合电子器件工程委员会)是一家半导体行业的标准化组织,旨在制定和发布相关行业标准,以促进半导体...
SAP Overview and Navigation SAP 概述和导航是 SAP 系统的入门课程,旨在为用户提供 SAP 系统的整体架构和导航方法的概述。本课程将介绍 SAP 系统的结构、模块、业务流程和导航方法,为用户提供了一个完整的 SAP ...
### SAP01_SAP_Overview_Part6:人力资源管理单元知识点详解 #### 一、时间数据记录选项 在SAP的人力资源管理系统(SAP HCM)中,针对员工的时间数据管理提供了多种灵活的方式进行记录。这些时间数据包括但不限于...
"SAP 概览"和"SAP Overview"这两份文档,无论是中文版还是英文版,都是为初学者提供的入门教程,旨在帮助读者快速理解SAP系统的基本概念、架构和功能。以下是这两份文档可能涵盖的关键知识点: 1. **SAP系统结构**...
"Unity Texture Overview Pro 5.0.7z" 是一个针对Unity纹理管理工具的专业版本,它可能包含了增强纹理处理和优化的工具集合。 在Unity中,纹理可以是图像文件,如.png、.jpg或.tiff,它们被应用到游戏对象的材质上...
根据提供的文件内容,我们可以提炼出有关“EtherCAT Slave Controller Overview”即EtherCAT从站控制器概述的知识点。首先,文件中提到的芯片型号和相关硬件组件都与EtherCAT技术在工业自动化领域中的应用密切相关。...
根据提供的文件信息,以下是对标题“targetlink overview guide”的详细知识点说明。 首先,“TargetLink”是一个工具,具体来讲,它很可能是指一个用于模型开发和代码生成的软件工具。从提供的内容可以看到,它与...
**Open Accelerator Infrastructure Project Overview (OAM+UBB)** OAM+UBB是Open Compute Project (OCP) 下的一个重要子项目,旨在构建开放的加速器基础设施,以快速适应人工智能(AI)和高性能计算(HPC)应用中...
其中,"cs_overview.pdf"文档详细阐述了在KITTI数据集中对象检测和跟踪的相关几何定义,这对于理解和分析该数据集至关重要。 首先,我们要理解对象坐标系统(Object Coordinate System, XYZ')。这个坐标系统是以每...