`
whitesock
  • 浏览: 483763 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

OpenJPA (7)

    博客分类:
  • EE
阅读更多

10 Miscellaneous Features
10.1 Restoring State
    JPA规范要求不应该使用rolled back objects,但是这些对象在OpenJPA中是有效的。可以通过配置openjpa.RestoreState 属性来控制是否将对象的状态回滚到事务前的状态。它有以下可选值:

  • none: 不回滚对象状态,但是对象变成hollow,在下次访问的时候会重新加载。
  • immutable: 回滚不可变的状态,可变的状态变成hollow,在下次访问的时候会重新加载。
  • all: 回滚所有状态。

10.2 Typing and Ordering
    当为对象的属性加载persistent state的时候,OpenJPA会检查这个属性在声明时或者无参构造函数中被赋值的类型。如果这个类型比声明的类型更精确,那么OpenJPA会用这个类型。如果你在初始化某个属性的时候使用了comparator,那么OpenJPA也会在每次加载persistent state的时候使用这个comparator。例如:

public class Company {

    // OpenJPA 会在每次加载数据的时候使用SalaryComparator。
    private Collection employeesBySal = new TreeSet(new SalaryComparator());
    private Map departments;

    public Company {
        // OpenJPA会使用TreeMap来保存departments 相关的persistent state。
        departments = new TreeMap();
    }
}
 

10.3 Proxies
10.3.1 Smart Proxies
    在运行时,OpenJPA可以通过代理跟踪entity 实例的属性是否被修改过,以便更有效地更新数据库。当设计persistent class的时候,应该尽可能将collection field映射成java.util.Set、java.util.TreeSet或java.util.HashSet。Smart proxy对这些类型可以进行更好的优化。

10.3.2 Large Result Set Proxies
    当遍历persistent collection 或者map属性的时候,ORM的缺省行为是把所有persistent state载入到内存中。然而,如果载入的数据量过大,那么可能会降低性能。OpenJPA为这些large result set属性使用特殊的代理。它并不在内存中缓存任何数据,相反它会访问数据库来获得相关的结果。例如large result set collection的contains方法会导致在数据库中执行类似于SELECT COUNT(*) WHERE的查询。类似地,在每次试图获得iterator的时候,OpenJPA会使用当前的large result set配置来执行特定的query。在调用iterator.next方法的时候,OpenJPA会按需载入结果对象。此时需要通过OpenJPAPersistence.close方法来释放资源,例如:

import org.apache.openjpa.persistence.*;

@Entity
public class Company {

    @ManyToMany
    @LRS
    private Collection<Employee> employees;

    ...
}

Collection employees = company.getEmployees(); // employees is a lrs collection
Iterator itr = employees.iterator();
while (itr.hasNext()) {
    process((Employee) itr.next());
}
OpenJPAPersistence.close(itr);
 

   Large result set 属性只能被声明成java.util.Collection 或者java.util.Map;它不能包含externalizer;Large result set proxy不能从一个entity 实例转移到另外一个entity 实例中,例如以下代码会导致提交时的一个错误:

Collection employees = company.getEmployees()  // employees is a lrs collection
company.setEmployees(null);
anotherCompany.setEmployees(employees);
 

10.3.3 Custom Proxies
    OpenJPA通过org.apache.openjpa.util.ProxyManager接口管理代理。其缺省的实现是org.apache.openjpa.util.ProxyManagerImpl。它有以下配置属性:

  • TrackChanges: 是否使用smart proxy,缺省是true。
  • AssertAllowedType: 在向collection或map中加入元素的时候,如果跟metadata 中声明的类型不符,是否抛出异常,缺省是false。

   以下是个简单的例子:

<property name="openjpa.ProxyManager" value="TrackChanges=false"/>

    缺省的proxy manager可以代理 Collection, List, Map, Queue, Date, or Calendar 等类上的标准方法,也可以代理定制类型,但是这些定制类型必须复合以下条件: 

  • Custom container types必须有一个公共的无参构造函数,或者一个公共的以Comparator为参数类型的构造函数。
  • Custom date types必须有一个公共的无参构造函数,或者一个公共的以long为参数 类型(代表当前的时间)的构造函数。
  • Other custom types必须有一个公共的无参构造函数,或者公共的拷贝构造函数。如果没有公共的拷贝构造函数,那么在进行拷贝的时候,首先会创建一个对象B,然后通过以A上getter方法的返回值为参数,调用B的setter方法。 因此你要确保通过这种方式,B是A的完整拷贝。

   如果某个custom classes无法满足以上条件,那么OpenJPA允许你定义你自己的proxy class和proxy manager。 


10.4 Externalization
    OpenJPA 支持通过custom field mappings 来完全控制entity class的field在datastore中怎样被保存、查询和加载。然而一个更轻量级的方法是使用externalization 。Externalization 支持通过指定某些方法来控制保存和加载的方式。需要注意的是,不能在@EmbeddedId字段上使用externalization。
    OpenJPA使用org.apache.openjpa.persistence.Externalizer annotation指定将某个属性转换为external value的方法名。如果指定一个non-static方法,那么OpenJPA会假定目标对象是被Externalizer标记的属性对象;如果指定一个static方法, 那么被OpenJPA会把被Externalizer标记的属性对象作为一个方法的参数。每个方法也可以接受一个StoreContext 型的参数。方法的返回值指定了缺省的external 类型。假设希望将某个CustomType类型的属性转换成String类型,那么可以采用以下的方法:

Method Extension
public String CustomType.toString() @Externalizer("toString")
public String CustomType.toString(StoreContext ctx) @Externalizer("toString")
public static String AnyClass.toString(CustomType ct) @Externalizer("AnyClass.toString")
public static String AnyClass.toString(CustomType ct, StoreContext ctx) @Externalizer("AnyClass.toString")

 

   OpenJPA使用org.apache.openjpa.persistence.Factory annotation指定根据external value初始化某个属性的方法名。 如果指定static方法,那么这个方法必须返回这个属性类型的一个实例。这个方法可以接受StoreContext 类型的一个参数。如果没有指定factory annotation,那么这个属性的class必须包含以external form为参数的构造函数,否则会抛出一个异常。假设希望将String类型转换成某个CustomType类型,那么可以采用以下的方法:

Method Extension
public CustomType(String str) none
public static CustomType CustomType.fromString(String str) @Factory("fromString")
public static CustomType CustomType.fromString(String str, StoreContext ctx) @Factory("fromString")
public static CustomType AnyClass.fromString(String str) @Factory("AnyClass.fromString")
public static CustomType AnyClass.fromString(String str, StoreContext ctx) @Factory("AnyClass.fromString")

 

   OpenJPA使用org.apache.openjpa.persistence.ExternalValues annotation指定external value的转换。 其value pairs用于指定Java和datastore的类型。如果datastore的类型不同于Java类型,那么通过org.apache.openjpa.persistence.Type annotation 指定datastore类型。如果externalized属性不是标准的persistent type,那么必须用org.apache.openjpa.persistence.Persistent annotation显式地进行标记。如果externalized 属性是可变的,而且不是collection、map和date类型,那么OpenJPA无法进行脏检查。可以手动进行标记为dirty,或者使用custom field proxy。以下是个简单的例子:

@Entity
public class Externalization {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	
	@Persistent
	@Externalizer("getName")
    @Factory("forName")
	private Class clazz;
	
	@Persistent
	@Factory("Externalization.stringToURL")
    @Externalizer("Externalization.urlToString")
	private URL url;
	
	@Basic
	@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
    @Type(int.class)
    private String size;
	
	public static URL stringToURL(String s) {
		try {
			return new URL(s);
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static String urlToString(URL url) {
		return url.toExternalForm();
	}
	
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("id: ").append(id);
		sb.append(", clazz: ").append(clazz);
		sb.append(", url: ").append(url);
		sb.append(", size: ").append(size);
		return sb.toString();
	}
}

EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Externalization e1 = new Externalization();
e1.setClazz(Externalization.class);
e1.setUrl(new URL("http://www.abc.com"));
e1.setSize("MEDIUM");
em.persist(e1);
em.getTransaction().commit();
em.close();

em = entityManagerFactory.createEntityManager();
Query q = em.createQuery("select m from Externalization m where m.url = 'http://www.abc.com'");
List<Externalization> r1 = (List<Externalization>)q.getResultList();
for(Iterator iter = r1.iterator(); iter.hasNext(); ) {
	System.out.println(iter.next().toString());
}
em.close();

    以上代码执行完毕后数据库中externalization表的数据如下: 

mysql> select * from externalization;
+----+-----------------+------+--------------------+
| id | clazz           | size | url                |
+----+-----------------+------+--------------------+
|  1 | Externalization |    8 | http://www.abc.com |
+----+-----------------+------+--------------------+
 

10.5 Fetch Groups
    Fetch groups是一组同时被加载的属性。之前介绍的Fetch Type指定了如何通过annotations指定某个属性是eagerly还是 lazily 加载。Fetch groups 则是提供了动态指定加载方式的能力。.

10.5.1 Custom Fetch Groups
    OpenJPA缺省fetch group中的属性都会被eagerly加载。此外可以通过org.apache.openjpa.persistence.FetchGroup annotation定义named fetch groups以便在运行时激活它。在加载的时候,OpenJPA会eagerly加载所有被激活的fetch groups中的属性。FetchGroup annotation有以下属性:

  • String name: fetch group 的全局名。以下名字被OpenJPA保留:default 、values、 all、none以及任何以jdo、jpa或openjpa开头的名字。
  • FetchAttribute[] attributes: fetch group中persistent fileds或者properties数组。
  • String[] fetchGroups: 包含在次fetch group中的其它fetch groups名。

   org.apache.openjpa.persistence.FetchAttribute annotation的属性如下: 

  • String name: persistent field 或者 property 名。
  • recursionDepth: eager-fetch 的递归深度,缺省是1(-1无限制)。

   Entity class的某个属性可以包含在任何的fetch group中,它也可以声明其load fetch group。缺省情况下,OpenJPA在第一次访问lazy-loaded属性的时候访问数据库。然而如果你直到当你访问某个lazy-loaded属性A的时候,你很可能也同时访问lazy-loaded 属性B和C,因此在一次数据库访问中同时加载A、B和C是更有效的。  
    通过org.apache.openjpa.persistence.LoadFetchGroup annotation为某个属性指定load fetch group。以下是个简单的例子:

import org.apache.openjpa.persistence.*;

@Entity
@FetchGroups({
    @FetchGroup(name="detail", attributes={
        @FetchAttribute(name="publisher"),
        @FetchAttribute(name="articles")
    })
})
public class Magazine {

   @ManyToOne(fetch=FetchType.LAZY)
   @LoadFetchGroup("detail")
   private Publisher publisher;
}
 

10.5.2 Custom Fetch Group Configuration
    OpenJPAEntityManager接口和OpenJPAQuery接口可以用于访问org.apache.openjpa.persistence.FetchPlan。FetchPlan通过以下方法维护当前活跃的fetch groups和maximum fetch depth:

public FetchPlan addFetchGroup(String group);
public FetchPlan addFetchGroups(String... groups);
public FetchPlan addFetchGroups(Collection groups);
public FetchPlan removeFetchGrop(String group);
public FetchPlan removeFetchGroups(String... groups);
public FetchPlan removeFetchGroups(Collection groups);
public FetchPlan resetFetchGroups();
public Collection<String> getFetchGroups();
public void clearFetchGroups();
public FetchPlan setMaxFetchDepth(int depth);
public int getMaxFetchDepth();

    Maximum fetch depth指定了加载时遍历对象的深度,缺省值是-1(无限制)。如果MaxFetchDepth是1,那么OpenJPA将会加载目标实例和它的直接relations; 如果MaxFetchDepth是2,那么OpenJPA会加载目标实例、直接relations和直接relations上的relations;如果MaxFetchDepth是-1,那么OpenJPA会加载目标实例以及所有的relatons直到到达对象图的边缘。当然以上的加载过程依赖于被加载属性是否是eagerly load,以及当前活跃的fetch group。以下是个简单的例子: 

OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
List results = kq.getResultList();

 

10.5.3 Per-field Fetch Configuration
    除了基于per-fetch-group 的配置外,OpenJPA也支持基于per-field的配置。通过以下方法将特定的field包含到当前的fetch plan中。

public FetchPlan addField(String field);
public FetchPlan addFields(String... fields);
public FetchPlan addFields(Class cls, String... fields);
public FetchPlan addFields(Collection fields);
public FetchPlan addFields(Class cls, Collection fields);
public FetchPlan removeField(String field);
public FetchPlan removeFields(String... fields);
public FetchPlan removeFields(Class cls, String... fields);
public FetchPlan removeFields(Collection fields);
public FetchPlan removeFields(Class cls, Collection fields);
public Collection<String> getFields();
public void clearFields();

    需要注意的是,以上方法中的field必须定义在指定的类中,而不是在其父类中。如果field publisher被定义在Publication中,而不是其子类Magazine中,那么必须用 addField (Publication.class, "publisher"),而不是addField (Magazine.class, "publisher")。出于性能上的考虑,OpenJPA并不对class name / field name 对进行验证。如果指定了不存在的class name / field name 对,那么会被OpenJPA忽略。以下是个简单的例子: 

OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
kem.getFetchPlan().addField(Magazine.class, "publisher");
Magazine mag = em.find(Magazine.class, magId);
10
0
分享到:
评论

相关推荐

    openjpa 写的一个例子

    7. **部署和测试**:将打包好的Web应用部署到Web服务器上,通过浏览器进行测试,查看OpenJPA是否能正常存取数据。 在"openjpademo"这个例子中,你可以期待看到如何设置和配置这些组件的详细步骤,以及如何编写相关...

    openjpa范例及实例工程

    默认情况下,当应用程序第一次获取实体标识时,OpenJPA 框架从数据库中一次性获取 50 个连续的实体标识缓存起来,当下一次应用程序需要获取实体标识时,OpenJPA 将首先检测缓存中是否存在实体标识,如果存在,Open...

    OpenJPA 2.2.1 API (CHM格式)

    OpenJPA  OpenJPA 是 Apache 组织提供的开源项目,它实现了 EJB 3.0 中的 JPA 标准,为开发者提供功能强大、使用简单的持久化数据管理框架。OpenJPA 封装了和关系型数据库交互的操作,让开发者把注意力集中在编写...

    openjpa 源码 下载 帮助开发人员调试

    OpenJPA,全称Open Java Persistence API,是Apache软件基金会的一个开源项目,它实现了Java持久化API(Java Persistence API,JPA),为Java开发者提供了一种标准的方式来管理和持久化应用程序中的对象。...

    Spring和openJPA集成

    **Spring和OpenJPA集成详解** 在Java世界中,Spring框架和OpenJPA(Open Java Persistence)是两个非常重要的组件。Spring作为一个全面的轻量级应用框架,提供了大量的功能,包括依赖注入、AOP(面向切面编程)、...

    Open JPA2 employee 简单例子

    OpenJPA2是一个开源的对象关系映射(ORM)框架,它是Java Persistence API(JPA)规范的实现。在这个“Open JPA2 employee简单例子”中,我们将深入理解如何使用OpenJPA2来处理数据库中的员工数据。这个示例将帮助...

    Spring中使用OpenJPA

    OpenJPA(Java Persistence API)则是Java平台上的一个ORM(对象关系映射)工具,它实现了JSR-317规范,使得开发者可以方便地在Java应用程序中操作数据库。本篇将详细讲解如何在Spring项目中集成并使用OpenJPA。 ...

    openJpa的应用,感觉还可以

    OpenJPA(Open Java Persistence API)是Apache软件基金会下的一个开源项目,它是Java持久层标准JPA(Java Persistence API)的一个实现。JPA是Java EE平台中的一个重要组件,用于管理和处理应用程序中的对象-关系...

    jsf、openJpa学习

    **JSF与OpenJPA整合** 涉及到在JSF应用中使用OpenJPA进行数据访问。这通常包括配置OpenJPA的数据源、实体管理器工厂,以及在JSF Managed Beans中注入实体管理器,以便在处理用户请求时执行CRUD操作。JSF的事件驱动...

    openjpa jar

    7. **插件扩展性**:Apache OpenJPA的设计使其具有高度的可扩展性,允许开发者通过插件自定义和扩展其行为,例如自定义查询解析器、持久化提供者等。 8. **数据库支持**:OpenJPA支持多种数据库,包括Oracle、MySQL...

    openJPA官方手册

    ### OpenJPA官方手册知识点概览 #### 一、引言 - **OpenJPA**:作为Apache项目的一部分,OpenJPA是一个开源的Java持久化框架(Java Persistence Framework),它支持Java Persistence API (JPA) 的规范。OpenJPA...

    通过 WebSphere Application Server V6.1 利用 OpenJPA

    安装OpenJPA的步骤通常包括下载OpenJPA的jar文件,将其添加到服务器的类路径中,并在服务器配置中指定OpenJPA作为默认的持久化提供者。 接下来,我们需要创建一个JPA项目。这涉及定义实体类,这些类代表数据库中的...

    Spring MVC+OpenJPA框架

    Spring MVC和OpenJPA是Java开发中常用的两个框架,它们分别在Web应用和持久层处理上发挥着重要作用。Spring MVC是Spring框架的一部分,用于构建高效、灵活的Web应用程序,而OpenJPA则是一个实现了Java Persistence ...

    OpenJPA API 文档 chm格式

    OpenJPA API 文档 chm格式

    Apache OpenJPA 2.1 User's Guide

    ### Apache OpenJPA 2.1 用户指南:Java Persistence API 的深入解析 #### 一、简介 Apache OpenJPA 2.1 是基于 Sun Microsystems 的 Java Persistence 2.0 API (JSR-317 JPA 2.0) 规范实现的一种透明持久化 Java ...

    openjpa:Apache OpenJPA

    Apache OpenJPA-自述文件 前言 感谢您下载此版本的Apache OpenJPA。 Apache OpenJPA是Java Persistence API规范的实现。 执照 此存储库的内容已根据Apache License 2.0 许可 更多信息 可以在openjpa-project子目录...

    openjpa-manual

    ### OpenJPA-Manual 关键知识点解析 #### 一、OpenJPA介绍 **1.1 关于本文档** 本文档旨在提供一个全面且深入的指南,帮助开发人员理解和掌握Java Persistence API(JPA)的核心概念及其在Apache OpenJPA中的实现...

    Openjpa2.2+Mysql+Maven+Servlet+JSP source code

    Openjpa2.2+Mysql+Maven+Servlet+JSP 博客源码: http://blog.csdn.net/shenhonglei1234/article/details/10394379

    apache-openjpa-2.2.1-binary

    7. **插件式架构**:OpenJPA的架构允许用户自定义策略和实现,以便适应不同的持久化需求和环境。 8. **兼容性**:Apache OpenJPA与多种Java应用服务器和数据库系统兼容,包括Tomcat、WebLogic、JBOSS、Oracle、...

Global site tag (gtag.js) - Google Analytics