- 浏览: 144710 次
- 来自: ...
文章分类
最新评论
-
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 1490EJB3 QL查询 EJB3的查询语言是一种和SQL非常类似的 ... -
Table
2008-07-08 12:18 1972Table Table用来定义entity主表的name,ca ... -
Overview
2008-07-07 19:33 8891 Overview Apache OpenJPA是J ... -
Metadata
2008-07-07 19:32 13073 Metadata 通过javax.p ... -
Miscellaneous Features
2008-07-07 19:29 129510 Miscellaneous Features 10.1 ... -
Object Locking
2008-07-07 19:27 13158 Object Locking 8.1 Configurin ... -
Query
2008-07-07 19:26 15486 Query 6.1 JPQL Queries 6.1.1Q ... -
jpa继承关系详解
2008-07-07 19:07 81777 Inheritance 对象使用引用以便关联到其它 ... -
JNDI简介
2008-05-29 17:03 1676JNDI简介 & 简单示例 ... -
ejb2 和 ejb3的区别
2008-03-31 13:39 4211EJB 3 和EJB 2.1 的区别 从整个EJB 规范的 ...
相关推荐
NULL 博文链接:https://lyndon-lin.iteye.com/blog/856002
其中Hibernate每次都需要手动创建SessionFactory,Session,手动开启提交关闭事务。而这一切操作完全是由Spring来代替。使持久层更加方便,使开发人员减少持久层操作,把注意力放到业务上。
SSH项目改为Spingboot项目,将项目中部分需要调用存储过程的部分用entityManagerFactory.unwrap(SessionFactory.class).openSession()来获取Session实现后发现项目访问数据库超过十次就会挂掉,原因是Springboot...
javax.persistence.EntityManagerFactory.class javax.persistence.EntityNotFoundException.class javax.persistence.EntityResult.class javax.persistence.EntityTransaction.class javax.persistence.Enumerated...
9.5.3 访问EntityManagerFactory 9.6 小结 第10章 事务和并发 10.1 事务本质 10.1.1 数据库和系统事务 10.1.2 Hibernate应用程序中的事务 10.1.3 使用Java Persistence的事务 10.2 ...
Contents at a Glance Foreword . . . . . . . . ....About the Author ....About the Technical Reviewers ....Acknowledgments....Introduction ....■CHAPTER 1 Introduction ....■CHAPTER 2 Structure of the NetBeans Platform ....
Not Using Commons Logging ................................................................... 12 Using SLF4J ..............................................................................................
使用自定义的EntityManagerFactory vii. 67.7. 使用两个EntityManagers viii. 67.8. 使用普通的persistence.xml ix. 67.9. 使用Spring Data JPA和Mongo仓库 x. 67.10. 将Spring Data仓库暴露为REST端点 vii. 68. ...
I. Spring Boot Documentation 1. About the Documentation 2. Getting Help 3. First Steps 4. Working with Spring Boot 5. Learning about Spring Boot Features 6. Moving to Production 7. Advanced Topics ...
通过参考和引用传智播客的免费教程,将springmvc4.1.6与hibernate4.3.10提供的JPA实现整合,使用mysql5.6.25,在MyEclipse2014中测试通过。可以作为web开发的基础框架使用。 使用说明: ... 2.po中的items使用jpa注解。...
Not Using Commons Logging ................................................................... 12 Using SLF4J ..............................................................................................
主要包括Persistence、EntityManagerFactory、EntityManager和EntityTransaction的具体使用
本篇文章主要介绍了详解基于Spring Boot与Spring Data JPA的多数据源配置,非常具有实用价值,需要的朋友可以参考下
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/...
集成器在commons / src / main / resources / META-INF / services / org.hibernate.integrator.spi.Integrator中声明该文件仅引用ExoJpaEntityScanner 构建EntityManagerFactory时,Hibernate会调用...
EntityManager,EntityManagerFactory的方法链接 改进的查询生成器 延迟迭代和结果集分页(适用于大型结果集) 可以将结果集返回为 可以将结果集返回为 Observable RichEntityManager.run句柄尝试捕获最终噪声以...
ArquillianDemo01 版本 1:在基本 JSF 和 JDBC 程序中演示 Arquillian 的... 被测试的方法使用了 JPA,它给出了一条错误消息,指出它无法检索 EntityManagerFactory。 该程序的一个类似版本仅使用注入的 DataSource 和
Spring Data 简介 SpringData提供了针对数据库(包括SQL和NOSQL)的整合方案,对Hibernate JPA、Jedis等工具的api进行高级的封装,为我们提供简单方便地操作接口。...entityManagerFactory、transactionManager
如果您必须了解一件事才能成功使用 JPA(Java 持久性 API),那就是缓存的概念。... EntityManagerFactory 创建一个 EntityManager(因此也创建一个 PersistenceContext/Cache) ###比较 RESOURCE_LOCAL 和 J
### jpa-eclipselink ... 实体管理器工厂(名称为entityManagerFactory的bean) JPA事务管理器(名称为transactionManager的bean) 自动配置数据源 自动扫描实体(@EntityScan) 没有persistence.xml的