本文最新版已更新至:http:///2012/12/30/JPA.htmlJPA定义了Java ORM及实体操作API的标准。本文摘录了JPA的一些关键信息以备查阅。 如果有hibernate的基础,通过本文也可以快速掌握JPA的基本概念及使用。 Table of Contents1 JPA概述JPA(Java Persistence API,Java持久化API),定义了对象-关系映射(ORM)以及实体对象持久化的标准接口。 JPA是JSR-220(EJB3.0)规范的一部分,在JSR-220中规定实体对象(EntityBean)由JPA进行支持。 所以JPA不局限于EJB3.0,而是作为POJO持久化的标准规范,可以脱离容器独立运行,开发和测试更加方便。 JPA在应用中的位置如下图所示:
JPA维护一个Persistence Context(持久化上下文),在持久化上下文中维护实体的生命周期。主要包含三个方面的内容:
JPA的主要API都定义在javax.persistence包中。如果你熟悉Hibernate,可以很容易做出对应:
2 实体生命周期实体生命周期是JPA中非常重要的概念,描述了实体对象从创建到受控、从删除到游离的状态变换。对实体的操作主要就是改变实体的状态。 JPA中实体的生命周期如下图:
EntityManager提供一系列的方法管理实体对象的生命周期,包括:
如果使用了事务管理,则事务的commit/rollback也会改变实体的状态。 3 实体关系映射(ORM)3.1 基本映射
3.2 ID生成策略ID对应数据库表的主键,是保证唯一性的重要属性。JPA提供了以下几种ID生成策略
3.3 关联关系JPA定义了one-to-one、one-to-many、many-to-one、many-to-many 4种关系。 对于数据库来说,通常在一个表中记录对另一个表的外键关联;对应到实体对象,持有关联数据的一方称为owning-side,另一方称为inverse-side。 为了编程的方便,我们经常会希望在inverse-side也能引用到owning-side的对象,此时就构建了双向关联关系。 在双向关联中,需要在inverse-side定义mappedBy属性,以指明在owning-side是哪一个属性持有的关联数据。 对关联关系映射的要点如下:
其中 many-to-many关系的owning-side可以使用@JoinTable声明自定义关联表,比如Book和Author之间的关联表: @JoinTable(name = "BOOKAUTHOR", joinColumns = { @JoinColumn(name = "BOOKID", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "AUTHORID", referencedColumnName = "id") }) 关联关系还可以定制延迟加载和级联操作的行为(owning-side和inverse-side可以分别设置): 通过设置fetch=FetchType.LAZY 或 fetch=FetchType.EAGER来决定关联对象是延迟加载或立即加载。 通过设置cascade={options}可以设置级联操作的行为,其中options可以是以下组合:
3.4 继承关系JPA通过在父类增加@Inheritance(strategy=InheritanceType.xxx)来声明继承关系。A支持3种继承策略:
其中1和2能够支持多态,但是1需要允许字段为NULL,2需要多个JOIN关系;3最适合关系数据库,对多态支持不好。具体应用时根据需要取舍。 4 事件及监听通过在实体的方法上标注@PrePersist,@PostPersist等声明即可在事件发生时触发这些方法。 5 Query Language 查询语言JPA提供两种查询方式,一种是根据主键查询,使用EntityManager的find方法: T find(Class entityClass, Object primaryKey) 另一种就是使用JPQL查询语言。JPQL是完全面向对象的,具备继承、多态和关联等特性,和hibernate HQL很相似。 使用EntityManager的createQuery方法: Query createQuery(String qlString) 5.1 使用参数可以在JPQL语句中使用参数。JPQL支持命名参数和位置参数两种参数,但是在一条JPQL语句中所有的参数只能使用同一种类型。 举例如下:
Query query = em.createQuery("select p from Person p where p.personid=:Id"); query.setParameter("Id",new Integer(1));
Query query = em.createQuery("select p from Person p where p.personid=?1"); query.setParameter(1,new Integer(1)); 5.2 命名查询如果某个JPQL语句需要在多个地方使用,还可以使用@NamedQuery 或者 @NamedQueries在实体对象上预定义命名查询。 在需要调用的地方只要引用该查询的名字即可。 例如: @NamedQuery(name="getPerson", query= "FROM Person WHERE personid=?1") @NamedQueries({ @NamedQuery(name="getPerson1", query= "FROM Person WHERE personid=?1"), @NamedQuery(name="getPersonList", query= "FROM Person WHERE age>?1") }) Query query = em.createNamedQuery("getPerson"); 5.3 排序JPQL也支持排序,类似于SQL中的语法。例如: Query query = em.createQuery("select p from Person p order by p.age, p.birthday desc"); 5.4 聚合查询JPQL支持AVG、SUM、COUNT、MAX、MIN五个聚合函数。例如: Query query = em.createQuery("select max(p.age) from Person p"); Object result = query.getSingleResult(); String maxAge = result.toString(); 5.5 更新和删除JPQL不仅用于查询,还可以用于批量更新和删除。 如: Query query = em.createQuery("update Order as o set o.amount=o.amount+10"); //update 的记录数 int result = query.executeUpdate(); Query query = em.createQuery("delete from OrderItem item where item.order in(from Order as o where o.amount<100)"); query.executeUpdate(); query = em.createQuery("delete from Order as o where o.amount<100"); query.executeUpdate();//delete的记录数 5.6 更多与SQL类似,JPQL还涉及到更多的语法,可以参考:http://docs.oracle.com/cd/E11035_01/kodo41/full/html/ejb3_langref.html 6 事务管理JPA支持本地事务管理(RESOURCELOCAL)和容器事务管理(JTA),容器事务管理只能用在EJB/Web容器环境中。 事务管理的类型可以在persistence.xml文件中的“transaction-type”元素配置。 JPA中通过EntityManager的getTransaction()方法获取事务的实例(EntityTransaction),之后可以调用事务的begin()、commit()、rollback()方法。 |
|