- 浏览: 147457 次
- 来自: ...
文章分类
最新评论
-
fisher:
真心感谢楼主! 解决了困扰我几天的大问题啊!
EntityManagerFactory -
悲剧了:
太棒了,我们项目正在用这个
struts2 convention-plugin -
nforce_com:
...
jpa继承关系详解 -
guanchuangsheng:
精辟~~
总算明白了·~
桥接模式和适配器模式的区别 -
lping2:
强,写得太全面了
EntityManagerFactory
4 EntityManagerFactory
4.1 Overview
EntityManagerFactory可以被注入到应用中,也可以通过以下方式创建:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("openjpa");
Persistence.createEntityManagerFactory方法通过在类路径上查找META-INF目录中的persistence.xml文件来获得EntityManagerFactory的配置,persistence.xml文件中可以定义多个persistence-unit。其name属性值可以作为Persistence.createEntityManagerFactory方法的参数,transaction-type用来指定是使用JTA,还是使用局部事务。以下是个persistence.xml文件的例子:
Xml代码
<?xml version="1.0"?>
<persistence>
<persistence-unit name="openjpa" transaction-type="RESOURCE_LOCAL" >
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>tutorial.Animal</class>
<class>tutorial.Dog</class>
<class>tutorial.Rabbit</class>
<class>tutorial.Snake</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:tutorial_database"/>
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/>
<property name="openjpa.ConnectionUserName" value="sa"/>
<property name="openjpa.ConnectionPassword" value=""/>
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>
</properties>
</persistence-unit>
</persistence>
<?xml version="1.0"?>
<persistence>
<persistence-unit name="openjpa" transaction-type="RESOURCE_LOCAL" >
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>tutorial.Animal</class>
<class>tutorial.Dog</class>
<class>tutorial.Rabbit</class>
<class>tutorial.Snake</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:tutorial_database"/>
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/>
<property name="openjpa.ConnectionUserName" value="sa"/>
<property name="openjpa.ConnectionPassword" value=""/>
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>
</properties>
</persistence-unit>
</persistence> EntityManagerFactory 实例是重量级对象。每个EntityManagerFactory 实例可能要维护metadata cache、object state cache、EntityManager pool、connection pool等等资源。如果应用程序不再使用EntityManagerFactory,那么应该及时关闭它以便释放资源。如果在一个或多个EntityManager处于活跃状态时试图关闭EntityManagerFactory,那么会导致一个IllegalStateException。
4.2 Persistence Context
Persistence context包含一组entities,这些entities都有唯一的persistent identity。在persistence context中,EntityManager管理entities的生命周期,entities可以访问datastore来获取persistent state。当persistence context结束的时候,被EntityManager管理的所有entities都变成detached状态。Detached entities不再被EntityManager管理,也不能访问datastore。有两种类型的persistent context:transaction persistence context和extended persistence context。
4.2.1 Transaction Persistence Context
在transaction persistence context模型中,EntityManager为每一个事务开始一个新的persistence context。当事务被提交或者回滚后,persistence context也就自动结束,被EntityManager管理的所有entity都变成detached状态。此时如果访问entity上尚未被加载的字段(例如lazy fetch字段)会导致没有定义的结果。
如果不在事务中通过EntityManager访问datastore,那么EntityManager会对每一次方法调用都创建一个新的persistence context。当方法调用结束时,persistence context也自动结束。例如当在事务之外调用EntityManager.find方法,EntityManager会创建一个临时的persistence context,并在这个临时的persistence context中访问datastore。当EntityManager.find方法结束时,临时的persistence context自动结束,并且EntityManager.find方法会返回一个detached entity。如果用相同的identity object再次调用EntityManager.find方法,那么会得到一个新的detached entity。以下是个描述transaction persistence context模型的行为的例子:
Java代码
EntityManager em; // injected
...
// outside a transaction:
// each operation occurs in a separate persistence context, and returns
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);
...
// transaction begins:
// within a transaction, a subsequent lookup doesn't return any of the
// detached objects. however, two lookups within the same transaction
// return the same instance, because the persistence context spans the
// transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 != mag1 && mag3 != mag2);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag3);
...
// transaction commits:
// once again, each operation returns a new instance
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 != mag3);
EntityManager em; // injected
...
// outside a transaction:
// each operation occurs in a separate persistence context, and returns
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);
...
// transaction begins:
// within a transaction, a subsequent lookup doesn't return any of the
// detached objects. however, two lookups within the same transaction
// return the same instance, because the persistence context spans the
// transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 != mag1 && mag3 != mag2);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag3);
...
// transaction commits:
// once again, each operation returns a new instance
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 != mag3);
4.2.2 Extended Persistence Context
在extended persistence context模型中,不论是否在事务内,EntityManager在其整个生命周期内维护相同一个persistence context。所有通过EntityManager得到的entities都被EntityManager管理,只有在EntityManager被关闭,或者entity被序列化的时候,entity才变成detached状态。
以下是个描述extended persistence context模型的行为的例子:
Java代码
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager();
// persistence context active for entire life of EM, so only one entity
// for a given persistent identity
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 == mag1);
em.getTransaction().begin();
// same persistence context active within the transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 == mag1);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag1);
em.getTransaction.commit ();
// when the transaction commits, instance still managed
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 == mag1);
// instance finally becomes detached when EM closes
em.close();
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager();
// persistence context active for entire life of EM, so only one entity
// for a given persistent identity
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 == mag1);
em.getTransaction().begin();
// same persistence context active within the transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 == mag1);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag1);
em.getTransaction.commit ();
// when the transaction commits, instance still managed
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 == mag1);
// instance finally becomes detached when EM closes
em.close();
5 EntityManager
EntityManager接口的方法可以大致分为以下几类。
5.1 Transaction Association
Java代码
public EntityTransaction getTransaction ();
public EntityTransaction getTransaction (); EntityManager实例和EntityTransaction实例之间是一对一的关系。 通过getTransaction方法可以得到与EntityManager关联的EntityTransaction实例。
5.2 Entity Identity Management
EntityManager负责管理entities,以下的这些方法的行为会因persistence context(transaction persistence context或者extended persistence context)的不同而有差异。
Java代码
public <T> T find(Class<T> cls, Object oid);
public <T> T find(Class<T> cls, Object oid); find方法返回persistent identity指定的entity。 如果这个entity存在于当前的persistence context中,那么返回值是被缓存的对象;否则会创建一个新的entity,并从datastore中加载相关的persistent state。如果datastore不存在持有指定persistent identity的记录,那么这个方法返回null。 Java代码
public <T> T getReference(Class<T> cls, Object oid);
public <T> T getReference(Class<T> cls, Object oid); getReference方法与find相似。不同的是:如果缓存中没有指定的entity,EntityManager会创建一个新的entity,不是立即访问datastore(不加载persistent state),而是在第一次访问某个持久字段的时候才加载相应的persistent state。此外,getReference 方法不返回null,如果在datastore中找不到相应的entity,这个方法会抛出EntityNotFoundException。 Java代码
public boolean contains(Object entity);
public boolean contains(Object entity); 如果当前的persistence context 包含指定的entity,那么返回true;否则返回false。
5.3 Cache Management
Java代码
public void flush();
public void flush(); Flush方法把当前事务中所有的修改写入到datastore中。如果EntityManager没有连接到datastore,那么EntityManager首先会获取一个连接并一直持有到事务结束。Flush方法抛出的任何异常都会导致事务回滚。如果调用flush方法时没有一个活跃的事务,那么flush方法会抛出TransactionRequiredException。
Java代码
public FlushModeType getFlushMode();
public void setFlushMode(FlushModeType flushMode);
public FlushModeType getFlushMode();
public void setFlushMode(FlushModeType flushMode); EntityManager的FlushMode 属性用来指定是否在执行query之前进行flush。这可以确保当前事务中的任何修改会体现在query的结果中。此外也可以在query实例上设置FlushMode。它有以下两个可选值:
COMMIT: 只是在事务提交的时候flush。当前事务中的修改可能不会体现在query的结果中。
AUTO: 在需要的时候进行flush以确保当前事务中的任何修改都会体现在query的结果中。
OpenJPA 只在当前事务的任何修改可能会影响到将要执行的query的结果时才进行flush。
Java代码
public void clear();
public void clear(); Clear方法会结束当前的persistence context,被EntityManager管理的所有entities变成detached状态。
5.4 Query Factory
Java代码
public Query createQuery(String query);
public Query createQuery(String query); createQuery方法根据提供的Java Persistence Query Language (JPQL) string来创建一个query。Java代码
public Query createNamedQuery(String name);
public Query createNamedQuery(String name); createNamedQuery方法用来得到通过metadata定义的命名query。 Java代码
public Query createNativeQuery(String sql);
public Query createNativeQuery(String sql, Class resultCls);
public Query createNativeQuery(String sql, String resultMapping);
public Query createNativeQuery(String sql);
public Query createNativeQuery(String sql, Class resultCls);
public Query createNativeQuery(String sql, String resultMapping); 以上方法用来创建datastore特有的native queries。例如在关系型数据库中使用的Structured Query Language (SQL)。
5.5 Closing
Java代码
public boolean isOpen();
public void close();
public boolean isOpen();
public void close(); 当不再使用EntityManager 的时候,需要及时关闭它以便释放资源。如果EntityManager 已经关闭,那么除了调用isOpen 方法外,调用EntityManager上的其它方法会导致IllegalStateException。不能在一个事务正在进行中的时候关闭EntityManager。
5.6 Entity Lifecycle Management
5.6.1 public void persist(Object entity);
persist方法用于将新创建的entity纳入EntityManager的管理,在下一次的flush或者commit时,这个entity会被插入到datastore中。这个方法只能在一个活跃的事务环境中调用。它的行为如下:
如果是新entity,那么它会被EntityManager管理。
如果这个entity已经被EntityManager管理,那么会被忽略。
如果这个entity之前被remove,那么它会重新被管理。
如果这个entity的状态是detached,那么会导致IllegalArgumentException。
以下是个简单的例子:
Java代码
import java.util.Iterator;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.apache.openjpa.persistence.FetchAttribute;
import org.apache.openjpa.persistence.FetchGroup;
import org.apache.openjpa.persistence.FetchGroups;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="grade"),
@FetchAttribute(name="magazines")
})
})
public class Publisher {
private int id;
private String name;
private String grade;
private List<Magazine> magazines;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: " + getId());
sb.append(", name: " + getName());
sb.append(", grade: " + getGrade());
sb.append(", magazines[");
if(getMagazines() != null) {
for(Iterator<Magazine> iter = getMagazines().iterator(); iter.hasNext(); ) {
sb.append(iter.next().toString());
if(iter.hasNext()) {
sb.append("; ");
}
}
}
sb.append("]");
return sb.toString();
}
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic(fetch=FetchType.LAZY)
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@OneToMany(mappedBy="publisher", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Magazine> getMagazines() {
return magazines;
}
public void setMagazines(List<Magazine> magazines) {
this.magazines = magazines;
}
}
import java.util.Iterator;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.apache.openjpa.persistence.FetchAttribute;
import org.apache.openjpa.persistence.FetchGroup;
import org.apache.openjpa.persistence.FetchGroups;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="grade"),
@FetchAttribute(name="magazines")
})
})
public class Publisher {
private int id;
private String name;
private String grade;
private List<Magazine> magazines;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: " + getId());
sb.append(", name: " + getName());
sb.append(", grade: " + getGrade());
sb.append(", magazines[");
if(getMagazines() != null) {
for(Iterator<Magazine> iter = getMagazines().iterator(); iter.hasNext(); ) {
sb.append(iter.next().toString());
if(iter.hasNext()) {
sb.append("; ");
}
}
}
sb.append("]");
return sb.toString();
}
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic(fetch=FetchType.LAZY)
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@OneToMany(mappedBy="publisher", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Magazine> getMagazines() {
return magazines;
}
public void setMagazines(List<Magazine> magazines) {
this.magazines = magazines;
}
}Java代码
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name = "publisherId", referencedColumnName = "id")
private Publisher publisher;
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 Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
public static class MagazineId {
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
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;
}
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.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name = "publisherId", referencedColumnName = "id")
private Publisher publisher;
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 Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
public static class MagazineId {
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
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;
}
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();
}
}
}Java代码
Publisher p1 = new Publisher();
p1.setId(id);
p1.setName("publisher1");
p1.setGrade("excellent");
p1.setMagazines(new ArrayList<Magazine>());
Magazine m1 = new Magazine();
m1.setIsbn("isbn1");
m1.setTitle("title1");
m1.setPublisher(p1);
p1.getMagazines().add(m1);
Magazine m2 = new Magazine();
m2.setIsbn("isbn2");
m2.setTitle("title2");
m2.setPublisher(p1);
p1.getMagazines().add(m2);
EntityManagerem = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.persist(p1);
em.getTransaction().commit();
Publisher p1 = new Publisher();
p1.setId(id);
p1.setName("publisher1");
p1.setGrade("excellent");
p1.setMagazines(new ArrayList<Magazine>());
Magazine m1 = new Magazine();
m1.setIsbn("isbn1");
m1.setTitle("title1");
m1.setPublisher(p1);
p1.getMagazines().add(m1);
Magazine m2 = new Magazine();
m2.setIsbn("isbn2");
m2.setTitle("title2");
m2.setPublisher(p1);
p1.getMagazines().add(m2);
EntityManagerem = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.persist(p1);
em.getTransaction().commit();
5.6.2 public void remove(Object entity);
remove方法用于删除被管理的entity。在下一次的flush或者commit时,这个entity会从datastore中删除。这个方法只能在一个活跃的事务环境中调用。它的行为如下:
如果是新entity,那么会被忽略。
如果是已经被管理的entity,那么它会被删除。
如果这个entity之前被remove,那么会被忽略。
如果这个entity的状态是detached,那么会导致IllegalArgumentException。
5.6.3 public void refresh(Object entity);
refresh方法用于确保entity的persistent state和datastore中的persistent state同步。它的行为如下:
如果是新entity,那么会被忽略。
如果是已经被管理的entity,那么刷新它的persistent state。
如果这个entity之前被remove,那么会被忽略。
如果这个entity的状态是detached,那么会导致IllegalArgumentException。
5.6.4 public Object merge(Object entity);
有些情况下,你需要编辑一个处于detached状态的entity,然后重新将这个entity纳入到EntityManager的管理中,并将对其persistent state的修改更新到datastore中。Merge方法返回该entity受管理的一份拷贝。这个方法只能在一个活跃的事务环境中调用。它的行为如下:
如果是新entity,那么会创建该entity的一份拷贝,并将这份拷贝纳入EntityManager的管理。
如果是已经被管理的entity,那么会被忽略。
如果这个entity之前被remove,那么会导致IllegalArgumentException。
如果这个entity的状态是detached,如果EntityManager中已经管理了具有相同的identity的entity B,那么会将原始entity的persistent state拷贝到entity B中;否则会创建该entity的一份拷贝,并将这份拷贝纳入EntityManager的管理。
以下是个简单的例子:
Java代码
p1.setName("publisher2");
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.merge(obj);
em.getTransaction().commit();
p1.setName("publisher2");
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.merge(obj);
em.getTransaction().commit();
5.6.5 public void lock (Object entity, LockModeType mode);
lock方法通过指定的LockModeType 来对entity加锁。LockModeType 有以下两个可选值:
READ: 在其它事务中可以读取,但是不能更新。
WRITE: 在其它事务中不可以读取或更新。在当前事务提交后,无论被WRITE lock锁定的entities是否改变,其version将会自动增加。
5.6.6 Detach and Attach
除了JPA定义的detach和attach API之外,OpenJPA还支持更多的特性。例如OpenJPAEntityManager提供以下方法:
Java代码
public Object detach(Object pc);
public Object[] detachAll(Object... pcs);
public Collection detachAll(Collection pcs);
public Object detach(Object pc);
public Object[] detachAll(Object... pcs);
public Collection detachAll(Collection pcs); 以上的detach方法返回给定entity的detached状态的拷贝。在detach在当前事务中被修改过的entity之前,flush方法会被调用,以便将这些修改保存到datastore中。由于detached entity不能访问datastore,因此有时候需要在detach之前加载一些persistent state(例如某些lazy fetch字段)。尽管可以通过手工编码完成,OpenJPA也提供了一些特性来自动完成类似的工作。例如DetachState,它有以下可选值:
loaded: 保持已经加载的字段,对于没有加载的字段则保持不变。这是缺省值。
fetch-groups: 根据fetch group来决定需要加载的字段。
all: 加载所有的字段。
继续5.6.1中的例子:
Java代码
EntityManager em = entityManagerFactory.createEntityManager();
Publisher p2 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p2.toString());
EntityManager em = entityManagerFactory.createEntityManager();
Publisher p2 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p2.toString()); 以上例子中p2在em.close()之后变成detached状态。由于采用了缺省的DetachState,因此没有加载lazy fetch字段grade和magazines。输出如下:
id: 1, name: publisher1, grade: null, magazines[]
Java代码
em = entityManagerFactory.createEntityManager();
Publisher p4 = (Publisher)em.find(Publisher.class, id);
p4.getGrade();
p4.getMagazines();
em.close();
System.out.println(p4.toString());
em = entityManagerFactory.createEntityManager();
Publisher p4 = (Publisher)em.find(Publisher.class, id);
p4.getGrade();
p4.getMagazines();
em.close();
System.out.println(p4.toString()); 以上例子中p4在em.close()之后变成detached状态。虽然采用了缺省的DetachState,但是由于程序中显式访问了lazy fetch字段,所以grade和magazines被加载,并且在detach之后仍然可以访问。输出如下:
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
Java代码
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.ALL);
Publisher p5 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p5.toString());
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.ALL);
Publisher p5 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p5.toString()); 以上例子中p5在em.close()之后变成detached状态。由于采用了 DetachStateType.ALL,因此所有的lazy fetch字段在detach之前都自动被加载,并且在detach之后仍然可以访问。输出如下:
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
Java代码
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.FETCH_GROUPS);
((OpenJPAEntityManager)em).getFetchPlan().addFetchGroup("detail");
Publisher p6 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p6.toString());
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.FETCH_GROUPS);
((OpenJPAEntityManager)em).getFetchPlan().addFetchGroup("detail");
Publisher p6 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p6.toString()); 以上例子中p6在em.close()之后变成detached状态。由于采用了 DetachStateType. FETCH_GROUPS,而Publisher中名为"detail"的fetch group定义了要额外加载grade和magazines,因此grade和magazines被加载,并且在detach之后仍然可以访问。输出如下:
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
4.1 Overview
EntityManagerFactory可以被注入到应用中,也可以通过以下方式创建:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("openjpa");
Persistence.createEntityManagerFactory方法通过在类路径上查找META-INF目录中的persistence.xml文件来获得EntityManagerFactory的配置,persistence.xml文件中可以定义多个persistence-unit。其name属性值可以作为Persistence.createEntityManagerFactory方法的参数,transaction-type用来指定是使用JTA,还是使用局部事务。以下是个persistence.xml文件的例子:
Xml代码
<?xml version="1.0"?>
<persistence>
<persistence-unit name="openjpa" transaction-type="RESOURCE_LOCAL" >
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>tutorial.Animal</class>
<class>tutorial.Dog</class>
<class>tutorial.Rabbit</class>
<class>tutorial.Snake</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:tutorial_database"/>
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/>
<property name="openjpa.ConnectionUserName" value="sa"/>
<property name="openjpa.ConnectionPassword" value=""/>
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>
</properties>
</persistence-unit>
</persistence>
<?xml version="1.0"?>
<persistence>
<persistence-unit name="openjpa" transaction-type="RESOURCE_LOCAL" >
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>tutorial.Animal</class>
<class>tutorial.Dog</class>
<class>tutorial.Rabbit</class>
<class>tutorial.Snake</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:tutorial_database"/>
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/>
<property name="openjpa.ConnectionUserName" value="sa"/>
<property name="openjpa.ConnectionPassword" value=""/>
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>
</properties>
</persistence-unit>
</persistence> EntityManagerFactory 实例是重量级对象。每个EntityManagerFactory 实例可能要维护metadata cache、object state cache、EntityManager pool、connection pool等等资源。如果应用程序不再使用EntityManagerFactory,那么应该及时关闭它以便释放资源。如果在一个或多个EntityManager处于活跃状态时试图关闭EntityManagerFactory,那么会导致一个IllegalStateException。
4.2 Persistence Context
Persistence context包含一组entities,这些entities都有唯一的persistent identity。在persistence context中,EntityManager管理entities的生命周期,entities可以访问datastore来获取persistent state。当persistence context结束的时候,被EntityManager管理的所有entities都变成detached状态。Detached entities不再被EntityManager管理,也不能访问datastore。有两种类型的persistent context:transaction persistence context和extended persistence context。
4.2.1 Transaction Persistence Context
在transaction persistence context模型中,EntityManager为每一个事务开始一个新的persistence context。当事务被提交或者回滚后,persistence context也就自动结束,被EntityManager管理的所有entity都变成detached状态。此时如果访问entity上尚未被加载的字段(例如lazy fetch字段)会导致没有定义的结果。
如果不在事务中通过EntityManager访问datastore,那么EntityManager会对每一次方法调用都创建一个新的persistence context。当方法调用结束时,persistence context也自动结束。例如当在事务之外调用EntityManager.find方法,EntityManager会创建一个临时的persistence context,并在这个临时的persistence context中访问datastore。当EntityManager.find方法结束时,临时的persistence context自动结束,并且EntityManager.find方法会返回一个detached entity。如果用相同的identity object再次调用EntityManager.find方法,那么会得到一个新的detached entity。以下是个描述transaction persistence context模型的行为的例子:
Java代码
EntityManager em; // injected
...
// outside a transaction:
// each operation occurs in a separate persistence context, and returns
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);
...
// transaction begins:
// within a transaction, a subsequent lookup doesn't return any of the
// detached objects. however, two lookups within the same transaction
// return the same instance, because the persistence context spans the
// transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 != mag1 && mag3 != mag2);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag3);
...
// transaction commits:
// once again, each operation returns a new instance
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 != mag3);
EntityManager em; // injected
...
// outside a transaction:
// each operation occurs in a separate persistence context, and returns
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);
...
// transaction begins:
// within a transaction, a subsequent lookup doesn't return any of the
// detached objects. however, two lookups within the same transaction
// return the same instance, because the persistence context spans the
// transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 != mag1 && mag3 != mag2);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag3);
...
// transaction commits:
// once again, each operation returns a new instance
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 != mag3);
4.2.2 Extended Persistence Context
在extended persistence context模型中,不论是否在事务内,EntityManager在其整个生命周期内维护相同一个persistence context。所有通过EntityManager得到的entities都被EntityManager管理,只有在EntityManager被关闭,或者entity被序列化的时候,entity才变成detached状态。
以下是个描述extended persistence context模型的行为的例子:
Java代码
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager();
// persistence context active for entire life of EM, so only one entity
// for a given persistent identity
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 == mag1);
em.getTransaction().begin();
// same persistence context active within the transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 == mag1);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag1);
em.getTransaction.commit ();
// when the transaction commits, instance still managed
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 == mag1);
// instance finally becomes detached when EM closes
em.close();
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager();
// persistence context active for entire life of EM, so only one entity
// for a given persistent identity
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 == mag1);
em.getTransaction().begin();
// same persistence context active within the transaction
Magazine mag3 = em.find(Magazine.class, magId);
assertTrue(mag3 == mag1);
Magazine mag4 = em.find(Magazine.class (magId);
assertTrue(mag4 == mag1);
em.getTransaction.commit ();
// when the transaction commits, instance still managed
Magazine mag5 = em.find(Magazine.class, magId);
assertTrue(mag5 == mag1);
// instance finally becomes detached when EM closes
em.close();
5 EntityManager
EntityManager接口的方法可以大致分为以下几类。
5.1 Transaction Association
Java代码
public EntityTransaction getTransaction ();
public EntityTransaction getTransaction (); EntityManager实例和EntityTransaction实例之间是一对一的关系。 通过getTransaction方法可以得到与EntityManager关联的EntityTransaction实例。
5.2 Entity Identity Management
EntityManager负责管理entities,以下的这些方法的行为会因persistence context(transaction persistence context或者extended persistence context)的不同而有差异。
Java代码
public <T> T find(Class<T> cls, Object oid);
public <T> T find(Class<T> cls, Object oid); find方法返回persistent identity指定的entity。 如果这个entity存在于当前的persistence context中,那么返回值是被缓存的对象;否则会创建一个新的entity,并从datastore中加载相关的persistent state。如果datastore不存在持有指定persistent identity的记录,那么这个方法返回null。 Java代码
public <T> T getReference(Class<T> cls, Object oid);
public <T> T getReference(Class<T> cls, Object oid); getReference方法与find相似。不同的是:如果缓存中没有指定的entity,EntityManager会创建一个新的entity,不是立即访问datastore(不加载persistent state),而是在第一次访问某个持久字段的时候才加载相应的persistent state。此外,getReference 方法不返回null,如果在datastore中找不到相应的entity,这个方法会抛出EntityNotFoundException。 Java代码
public boolean contains(Object entity);
public boolean contains(Object entity); 如果当前的persistence context 包含指定的entity,那么返回true;否则返回false。
5.3 Cache Management
Java代码
public void flush();
public void flush(); Flush方法把当前事务中所有的修改写入到datastore中。如果EntityManager没有连接到datastore,那么EntityManager首先会获取一个连接并一直持有到事务结束。Flush方法抛出的任何异常都会导致事务回滚。如果调用flush方法时没有一个活跃的事务,那么flush方法会抛出TransactionRequiredException。
Java代码
public FlushModeType getFlushMode();
public void setFlushMode(FlushModeType flushMode);
public FlushModeType getFlushMode();
public void setFlushMode(FlushModeType flushMode); EntityManager的FlushMode 属性用来指定是否在执行query之前进行flush。这可以确保当前事务中的任何修改会体现在query的结果中。此外也可以在query实例上设置FlushMode。它有以下两个可选值:
COMMIT: 只是在事务提交的时候flush。当前事务中的修改可能不会体现在query的结果中。
AUTO: 在需要的时候进行flush以确保当前事务中的任何修改都会体现在query的结果中。
OpenJPA 只在当前事务的任何修改可能会影响到将要执行的query的结果时才进行flush。
Java代码
public void clear();
public void clear(); Clear方法会结束当前的persistence context,被EntityManager管理的所有entities变成detached状态。
5.4 Query Factory
Java代码
public Query createQuery(String query);
public Query createQuery(String query); createQuery方法根据提供的Java Persistence Query Language (JPQL) string来创建一个query。Java代码
public Query createNamedQuery(String name);
public Query createNamedQuery(String name); createNamedQuery方法用来得到通过metadata定义的命名query。 Java代码
public Query createNativeQuery(String sql);
public Query createNativeQuery(String sql, Class resultCls);
public Query createNativeQuery(String sql, String resultMapping);
public Query createNativeQuery(String sql);
public Query createNativeQuery(String sql, Class resultCls);
public Query createNativeQuery(String sql, String resultMapping); 以上方法用来创建datastore特有的native queries。例如在关系型数据库中使用的Structured Query Language (SQL)。
5.5 Closing
Java代码
public boolean isOpen();
public void close();
public boolean isOpen();
public void close(); 当不再使用EntityManager 的时候,需要及时关闭它以便释放资源。如果EntityManager 已经关闭,那么除了调用isOpen 方法外,调用EntityManager上的其它方法会导致IllegalStateException。不能在一个事务正在进行中的时候关闭EntityManager。
5.6 Entity Lifecycle Management
5.6.1 public void persist(Object entity);
persist方法用于将新创建的entity纳入EntityManager的管理,在下一次的flush或者commit时,这个entity会被插入到datastore中。这个方法只能在一个活跃的事务环境中调用。它的行为如下:
如果是新entity,那么它会被EntityManager管理。
如果这个entity已经被EntityManager管理,那么会被忽略。
如果这个entity之前被remove,那么它会重新被管理。
如果这个entity的状态是detached,那么会导致IllegalArgumentException。
以下是个简单的例子:
Java代码
import java.util.Iterator;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.apache.openjpa.persistence.FetchAttribute;
import org.apache.openjpa.persistence.FetchGroup;
import org.apache.openjpa.persistence.FetchGroups;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="grade"),
@FetchAttribute(name="magazines")
})
})
public class Publisher {
private int id;
private String name;
private String grade;
private List<Magazine> magazines;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: " + getId());
sb.append(", name: " + getName());
sb.append(", grade: " + getGrade());
sb.append(", magazines[");
if(getMagazines() != null) {
for(Iterator<Magazine> iter = getMagazines().iterator(); iter.hasNext(); ) {
sb.append(iter.next().toString());
if(iter.hasNext()) {
sb.append("; ");
}
}
}
sb.append("]");
return sb.toString();
}
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic(fetch=FetchType.LAZY)
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@OneToMany(mappedBy="publisher", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Magazine> getMagazines() {
return magazines;
}
public void setMagazines(List<Magazine> magazines) {
this.magazines = magazines;
}
}
import java.util.Iterator;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.apache.openjpa.persistence.FetchAttribute;
import org.apache.openjpa.persistence.FetchGroup;
import org.apache.openjpa.persistence.FetchGroups;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="grade"),
@FetchAttribute(name="magazines")
})
})
public class Publisher {
private int id;
private String name;
private String grade;
private List<Magazine> magazines;
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: " + getId());
sb.append(", name: " + getName());
sb.append(", grade: " + getGrade());
sb.append(", magazines[");
if(getMagazines() != null) {
for(Iterator<Magazine> iter = getMagazines().iterator(); iter.hasNext(); ) {
sb.append(iter.next().toString());
if(iter.hasNext()) {
sb.append("; ");
}
}
}
sb.append("]");
return sb.toString();
}
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic(fetch=FetchType.LAZY)
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@OneToMany(mappedBy="publisher", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Magazine> getMagazines() {
return magazines;
}
public void setMagazines(List<Magazine> magazines) {
this.magazines = magazines;
}
}Java代码
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name = "publisherId", referencedColumnName = "id")
private Publisher publisher;
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 Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
public static class MagazineId {
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
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;
}
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.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
@IdClass(Magazine.MagazineId.class)
public class Magazine {
@Id
private String isbn;
@Id
private String title;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name = "publisherId", referencedColumnName = "id")
private Publisher publisher;
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 Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
public static class MagazineId {
private String isbn;
private String title;
public MagazineId() {
}
public MagazineId(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
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;
}
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();
}
}
}Java代码
Publisher p1 = new Publisher();
p1.setId(id);
p1.setName("publisher1");
p1.setGrade("excellent");
p1.setMagazines(new ArrayList<Magazine>());
Magazine m1 = new Magazine();
m1.setIsbn("isbn1");
m1.setTitle("title1");
m1.setPublisher(p1);
p1.getMagazines().add(m1);
Magazine m2 = new Magazine();
m2.setIsbn("isbn2");
m2.setTitle("title2");
m2.setPublisher(p1);
p1.getMagazines().add(m2);
EntityManagerem = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.persist(p1);
em.getTransaction().commit();
Publisher p1 = new Publisher();
p1.setId(id);
p1.setName("publisher1");
p1.setGrade("excellent");
p1.setMagazines(new ArrayList<Magazine>());
Magazine m1 = new Magazine();
m1.setIsbn("isbn1");
m1.setTitle("title1");
m1.setPublisher(p1);
p1.getMagazines().add(m1);
Magazine m2 = new Magazine();
m2.setIsbn("isbn2");
m2.setTitle("title2");
m2.setPublisher(p1);
p1.getMagazines().add(m2);
EntityManagerem = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.persist(p1);
em.getTransaction().commit();
5.6.2 public void remove(Object entity);
remove方法用于删除被管理的entity。在下一次的flush或者commit时,这个entity会从datastore中删除。这个方法只能在一个活跃的事务环境中调用。它的行为如下:
如果是新entity,那么会被忽略。
如果是已经被管理的entity,那么它会被删除。
如果这个entity之前被remove,那么会被忽略。
如果这个entity的状态是detached,那么会导致IllegalArgumentException。
5.6.3 public void refresh(Object entity);
refresh方法用于确保entity的persistent state和datastore中的persistent state同步。它的行为如下:
如果是新entity,那么会被忽略。
如果是已经被管理的entity,那么刷新它的persistent state。
如果这个entity之前被remove,那么会被忽略。
如果这个entity的状态是detached,那么会导致IllegalArgumentException。
5.6.4 public Object merge(Object entity);
有些情况下,你需要编辑一个处于detached状态的entity,然后重新将这个entity纳入到EntityManager的管理中,并将对其persistent state的修改更新到datastore中。Merge方法返回该entity受管理的一份拷贝。这个方法只能在一个活跃的事务环境中调用。它的行为如下:
如果是新entity,那么会创建该entity的一份拷贝,并将这份拷贝纳入EntityManager的管理。
如果是已经被管理的entity,那么会被忽略。
如果这个entity之前被remove,那么会导致IllegalArgumentException。
如果这个entity的状态是detached,如果EntityManager中已经管理了具有相同的identity的entity B,那么会将原始entity的persistent state拷贝到entity B中;否则会创建该entity的一份拷贝,并将这份拷贝纳入EntityManager的管理。
以下是个简单的例子:
Java代码
p1.setName("publisher2");
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.merge(obj);
em.getTransaction().commit();
p1.setName("publisher2");
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.merge(obj);
em.getTransaction().commit();
5.6.5 public void lock (Object entity, LockModeType mode);
lock方法通过指定的LockModeType 来对entity加锁。LockModeType 有以下两个可选值:
READ: 在其它事务中可以读取,但是不能更新。
WRITE: 在其它事务中不可以读取或更新。在当前事务提交后,无论被WRITE lock锁定的entities是否改变,其version将会自动增加。
5.6.6 Detach and Attach
除了JPA定义的detach和attach API之外,OpenJPA还支持更多的特性。例如OpenJPAEntityManager提供以下方法:
Java代码
public Object detach(Object pc);
public Object[] detachAll(Object... pcs);
public Collection detachAll(Collection pcs);
public Object detach(Object pc);
public Object[] detachAll(Object... pcs);
public Collection detachAll(Collection pcs); 以上的detach方法返回给定entity的detached状态的拷贝。在detach在当前事务中被修改过的entity之前,flush方法会被调用,以便将这些修改保存到datastore中。由于detached entity不能访问datastore,因此有时候需要在detach之前加载一些persistent state(例如某些lazy fetch字段)。尽管可以通过手工编码完成,OpenJPA也提供了一些特性来自动完成类似的工作。例如DetachState,它有以下可选值:
loaded: 保持已经加载的字段,对于没有加载的字段则保持不变。这是缺省值。
fetch-groups: 根据fetch group来决定需要加载的字段。
all: 加载所有的字段。
继续5.6.1中的例子:
Java代码
EntityManager em = entityManagerFactory.createEntityManager();
Publisher p2 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p2.toString());
EntityManager em = entityManagerFactory.createEntityManager();
Publisher p2 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p2.toString()); 以上例子中p2在em.close()之后变成detached状态。由于采用了缺省的DetachState,因此没有加载lazy fetch字段grade和magazines。输出如下:
id: 1, name: publisher1, grade: null, magazines[]
Java代码
em = entityManagerFactory.createEntityManager();
Publisher p4 = (Publisher)em.find(Publisher.class, id);
p4.getGrade();
p4.getMagazines();
em.close();
System.out.println(p4.toString());
em = entityManagerFactory.createEntityManager();
Publisher p4 = (Publisher)em.find(Publisher.class, id);
p4.getGrade();
p4.getMagazines();
em.close();
System.out.println(p4.toString()); 以上例子中p4在em.close()之后变成detached状态。虽然采用了缺省的DetachState,但是由于程序中显式访问了lazy fetch字段,所以grade和magazines被加载,并且在detach之后仍然可以访问。输出如下:
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
Java代码
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.ALL);
Publisher p5 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p5.toString());
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.ALL);
Publisher p5 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p5.toString()); 以上例子中p5在em.close()之后变成detached状态。由于采用了 DetachStateType.ALL,因此所有的lazy fetch字段在detach之前都自动被加载,并且在detach之后仍然可以访问。输出如下:
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
Java代码
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.FETCH_GROUPS);
((OpenJPAEntityManager)em).getFetchPlan().addFetchGroup("detail");
Publisher p6 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p6.toString());
em = entityManagerFactory.createEntityManager();
((OpenJPAEntityManager)em).setDetachState(DetachStateType.FETCH_GROUPS);
((OpenJPAEntityManager)em).getFetchPlan().addFetchGroup("detail");
Publisher p6 = (Publisher)em.find(Publisher.class, id);
em.close();
System.out.println(p6.toString()); 以上例子中p6在em.close()之后变成detached状态。由于采用了 DetachStateType. FETCH_GROUPS,而Publisher中名为"detail"的fetch group定义了要额外加载grade和magazines,因此grade和magazines被加载,并且在detach之后仍然可以访问。输出如下:
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
发表评论
-
EJB3 QL查询
2008-07-17 15:57 1548EJB3 QL查询 EJB3的查询语言是一种和SQL非常类似的 ... -
Table
2008-07-08 12:18 2022Table Table用来定义entity主表的name,ca ... -
Overview
2008-07-07 19:33 9471 Overview Apache OpenJPA是J ... -
Metadata
2008-07-07 19:32 13443 Metadata 通过javax.p ... -
Miscellaneous Features
2008-07-07 19:29 134410 Miscellaneous Features 10.1 ... -
Object Locking
2008-07-07 19:27 13518 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 82337 Inheritance 对象使用引用以便关联到其它 ... -
JNDI简介
2008-05-29 17:03 1710JNDI简介 & 简单示例 ... -
ejb2 和 ejb3的区别
2008-03-31 13:39 4249EJB 3 和EJB 2.1 的区别 从整个EJB 规范的 ...
相关推荐
public LocalContainerEntityManagerFactoryBean entityManagerFactory1() { // 配置实体管理工厂1 } @Bean public DataSource dataSource2() { // 配置数据源2 } @Bean public ...
标题 "java.lang.NoClassDefFoundError: javax/persistence/EntityListener" 提到的问题是一个常见的Java运行时异常,通常表示在类加载时找不到指定的类定义。这个错误在Java应用程序或Web应用中出现,可能是因为...
2. **EntityManagerFactory创建**:基于解析后的配置,创建出一个适合于JPA数据库访问的`EntityManagerFactory`实例。 3. **资源管理**:管理`EntityManagerFactory`的生命周期,例如创建、关闭等操作。 #### 三、...
JPA的核心API包括四个主要组件:`Persistence`、`EntityManagerFactory`、`EntityManager`和`EntityTransaction`,它们共同构成了JPA的数据访问框架。 **1. `Persistence`** `Persistence`接口是JPA的入口点,它...
其中Hibernate每次都需要手动创建SessionFactory,Session,手动开启提交关闭事务。而这一切操作完全是由Spring来代替。使持久层更加方便,使开发人员减少持久层操作,把注意力放到业务上。
JPA的核心概念主要包括实体(Entity)、实体管理器(EntityManager)、实体工厂(EntityManagerFactory)以及查询语言(JPQL): 1. **实体(Entity)**:在JPA中,实体是对数据库表的抽象,通常是一个Java类,通过...
7. **EntityManagerFactory**: 介绍了如何创建和使用 EntityManagerFactory 实例。 8. **EntityManager**: 详细讲解了 EntityManager 的使用方法及其生命周期管理功能。 #### 三、关键知识点详解 ##### 3.1 JPA ...
2. 配置EntityManagerFactory:使用LocalEntityManagerFactoryBean创建EntityManagerFactory实例。 3. 配置事务管理器:使用JpaTransactionManager,与EntityManagerFactory配合处理事务。 4. 配置数据源:定义...
public PlatformTransactionManager transactionManager1(EntityManagerFactory entityManagerFactory1) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager....
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory); } } ``` 类似地,在`SecondaryDataSourceConfig`中配置第...
public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) { // 配置事务管理器 } ``` 在代码中,我们可以通过`@Resource`注解注入...
<property name="entityManagerFactory" ref="entityManagerFactory"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> ``` 四、持久层...
private EntityManagerFactory entityManagerFactory; public void addUser(User user) { EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin...
- **配置和获取**:通过`Persistence.createEntityManagerFactory()`创建EntityManagerFactory,然后用`EntityManagerFactory.createEntityManager()`获取EntityManager实例。 - **生命周期和状态**:实体有瞬时态...
2. **基于EntityManagerFactory创建**:如果已经有一个`EntityManagerFactory`实例(通常用于JPA持久化),可以通过`RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder().entityManagerFactory(this.emf)`...
- **获取EntityManagerFactory**:可以通过`Persistence.createEntityManagerFactory()` 方法创建EntityManagerFactory实例。 - **获取EntityManager**:通过EntityManagerFactory的`createEntityManager()` 方法...
通常,你会在应用程序启动时创建一个`EntityManagerFactory`,然后在整个应用程序生命周期内重复使用它。 3. `Entity`: 这是一个注解,标记在Java类上表示该类是一个数据库实体。JPA通过这个注解知道如何将类映射到...
本文主要介绍三种方法,包括使用`entityManagerFactory.unwrap(SessionFactory.class).openSession()`、直接使用`EntityManager`的`createStoredProcedureQuery()`方法以及通过`ProcedureCall`接口。在转换SSH项目到...
这些配置类通常会继承`AbstractJpaConfiguration`,并重写`entityManagerFactoryBean()`和`jdbcTemplate()`方法,为每个数据源创建EntityManagerFactory和JdbcTemplate实例。例如: ```java @Configuration @...
- **EntityManagerFactory的角色**:`EntityManagerFactory`作为`EntityManager`的工厂类,它包含了当前对象-关系映射的元数据信息。每个`EntityManagerFactory`代表了一个持久化单元(Persistence Unit),这相当于...