JPA (Java Persistence API)概述

在ORM的概念大行其道之际,JavaEE平台也不得不做出适当调整,直接在平台层提供了对象/关系映射机制JPA,并结合了其重要的Entity JavaBean。JPA概括起来包括如下3个部分:

  • 对象/关系映射元数据及API
  • Java对象查询语言
  • Java Criteria查询API 


1. Entity

JPA 中的Entity是一种可持久化的域对象。一个Entity类对应关系数据库中的一张表,一个Entity实例对应关系数据库中的表的一行记录。

一个Entity类的定义,需要遵守如下规则:

  • 由@javax.persistence.Entity标注
  • 至少拥有一个public或protected的、无参数的构造函数
  • 不能是final的类,也不能包含任何final的方法或可持久化的类变量
  • 可持久化的类变量不能是public的,只能被Entity类中的方法直接访问(可以通过getter方法被应用间接访问)
  • 可以继承自任何类(Entity类或非Entity类),也可以被任何类继承
  • 必要情况下实现Serializable接口

Entity实例的持久化就是对其中类变量或属性的持久化。根据表现形式,可以分为持久化字段(Persistent Fields)和持久化属性(Persistent Properties)。

1)持久化字段

Entity类中的可持久化的类变量也被称为持久化字段。持久化字段的持久化标注是定义在类变量上的。通常,持久化字段将被存储到对应的数据库中,除非以下情况:

  • 持久化字段同时被@javax.persistence.Transient标注
  • 持久化字段同时被Java关键字transient修饰

2)持久化属性

持久化属性的持久化标注是定义在类变量的getter方法上的。持久化属性都必须拥有getter/setter方法。如果类变量被如下定义,则不能在该类变量的getter方法上设置持久化标注,即这样的类变量不可能同时是持久化属性:

  • 类变量被@javax.persistence.Transient标注
  • 类变量被Java关键字transient修饰

2. Entity Relationship

Entity和Entity之间的关系称为Entity Relationship,Entity关系的表示是通过Entity类中的关系字段或关系属性。Entity关系的类型(用以修饰关系字段或关系属性的标注)如下:

  • @javax.persistence.OneToOne
  • @javax.persistence.OneToMany
  • @javax.persistence.ManyToOne
  • @javax.persistence.ManyToMany

1)Entity关系的方向性

Entity关系具有方向性,一个Entity关系所涉及的双方Entity,必然有一个owning方,另外还可以有一个inverse方。

Entity关系的定义可以是单向的,也可以是双向的:

  • 单向,相互关联的两个Entity只有一个通过关系标注引用对方

             拥有标注的这个Entity被称为关系的owning方(对应数据库的表中有外键)

  • 双向,相互关联的两个Entity都通过关系标注彼此互相引用对方

             其中一个Entity是关系的owning方,另一个Entity是关系的inverse方(标注中带有mappedBy)。

注意:

OneToOne的关系中,对应数据库的表中有外键的是owning方;

OneToManyManyToOne的关系中,多方必须是owning方(外键必须在多方);

ManyToMany的关系中,任意一方都可以是owning方(两方都有外键);

Entity Relationships的方向性决定了在查询时从一个Entity是否可以访问关联的Entity。


2)Entity关系的级联操作Cascade


3. Entity类的继承

Entity类支持类的继承和多态。Entity类(@javax.persistence.Entity标注修饰)与非Entity类(没有任何持久化标注修饰)之间可以互相继承。

Entity类可以是抽象类,也可以是具体类。抽象Entity类可以被用于查询语句,也可以被EntityManager管理。但因为抽象类不能被实例化,所以查询语句中查询的对象如果是抽象Entity类,则事实上是对该抽象Entity类的所有具体类的查询。

非Entity类中定义的任何持久化字段或持久化属性都将被忽略。即使是非Entity类被Entity类继承了,但是在非Entity类中包含的任何持久化字段或持久化属性仍将被忽略。非Entity类不能被用于查询语句,也不能被EntityManager管理。

有一种特殊的非Entity类被称为Mapped Superclass(@javax.persistence.MappedSuperclass标注修饰),其中也可以包含持久化字段或持久化属性。Mapped Superclass往往定义通用的持久化字段或持久化属性,并被Entity类继承。Mapped Superclass可以是抽象类,也可以是具体类。Mapped Superclass因为不是Entity,所以不能被用于查询语句,也不能被EntityManager管理。

对于一组有继承关系的Entity类,他们与数据库中的表之间的映射策略可以配置。其中处于继承关系顶端的根Entity类必须使用@javax.persistence.Inheritance标注。具体的映射策略如下:

  • 整个继承关系的Entity类一起对应数据库中的一个表(默认)

             @javax.persistence.Inheritance(strategy=”javax.persistence.InheritanceType.SINGLE_TABLE”)

  • 每个具体的Entity类对应数据库中的一个表(不推荐)

             @javax.persistence.Inheritance(strategy=”javax.persistence.InheritanceType.TABLE_PER_CLASS”)

  • “join”策略,通用父Entity类和具体子Entity类都对应数据库中的一个表,使用时连接起来

             @javax.persistence.Inheritance(strategy=”javax.persistence.InheritanceType.JOINED”)


4. 对Entity的管理EntityManager

javax.persistence.EntityManager对象负责管理位于同一数据库中的所有Entity。

一个EntityManager对象就对应一个持久化上下文(persistencecontext),即一个特定的数据存储,所有该数据存储中的Entity实例都由对应的EntityManager对象管理。事实上,持久化上下文实现对Entity实例的具体操作,而javax.persistence.EntityManager接口中定义的方法只是用于与持久化上下文交互。

  • Container-Managed Entity Manager

在JTA事务中往往要访问持久化上下文,这时只要将该持久化上下文对应的EntityManager注入到应用中即可。对于JavaEE容器管理的EntityManager,无需在应用类之间传递EntityManager,JavaEE容器负责EntityManager的生命周期管理,并且在整个JTA事务中可用。

@javax.persistence.PersistenceContext
EntityManager em;

  • Application-Managed Entity Manager

由于javax.persistence.EntityManager的实例不是线程安全的,为了线程安全地控制对数据库的访问,应用可以使用javax.persistence.EntityManagerFactory创建一个特有的EntityManager并关联一个独立的持久化上下文(称为持久化单元)。持久化单元的定义位于persistence.xml 文件中。

通过EntityManagerFactory创建的EntityManager,必须嵌入到事务操作的开始和结束之间才能够加入事务,即应用管理的EntityManager只能在应用管理的事务中使用。应用必须EntityManager及其持久化上下文的生命周期。

@javax.persistence.PersistenceUnit
EntityManagerFactory emf;
EntityManager em = emf.createEntityManager();

5. EntityManager对Entity的生命周期管理

Entity实例有如下4种状态:

  • new,没有与持久化上下文关联,也没有持久标识
  • managed,与持久化上下文关联,也有持久标识
  • detached,没有与持久化上下文关联,但因为曾经关联过,所以有持久标识
  • removed,与持久化上下文关联,也有持久标识,将被定期从数据库中删除

 Entity实例中的数据与数据库中数据进行同步的发生:

  • Entity实例所在的事务被提交
  • 或者调用了EntityManager的flush()

 

6. 对Entity的查询

JPA提供如下2种查询Entity的方法:

  • Java Persistence query language (JPQL),类似于SQL

              查询结果需要进行类型转换

  • Criteria API, 一组Java API

              类型安全

              执行性能高

              编程复杂


7. JPA的锁机制

  • 乐观锁(默认)

数据库的表中有version列(Entity类中的字段或属性使用@javax.persistence.Version标注),应用只能读取不能修改。

事务提交时申请short-termlock,失败则抛出javax.persistence.OptimisticLockException异常并回滚事务。

  • 悲观锁,适合于数据变化特别频繁的数据库

事务在创建的时候就开始持有long-termlock,直至事务结束。

 

JPA提供的锁模式:

  • javax.persistence.LockModeType.OPTIMISTIC
  • javax.persistence.LockModeType.OPTIMISTIC_FORCE_INCREMENT
  • javax.persistence.LockModeType.PESSIMISTIC_READ
  • javax.persistence.LockModeType.PESSIMISTIC_WRITE
  • javax.persistence.LockModeType.PESSIMISTIC_FORCE_INCREMENT
  • javax.persistence.LockModeType.READ(不建议使用,等价于OPTIMISTIC)
  • javax.persistence.LockModeType.WRITE(不建议使用,等价于OPTIMISTIC_FORCE_INCREMENT)
  • javax.persistence.LockModeType.NONE

8. JPA的二级缓存

二级缓存是在JavaEE服务器上对一个持久化上下文中Entity的本地存储,对于应用来说是透明的。

JPA提供的缓存模式:

  • ALL,缓存持久化上下文中的所有Entity
  • NONE,不缓冲任何Entity
  • ENABLE_SELECTIVE,只缓存@javax.persistence.Cacheable标注的Entity
  • DISABLE_SELECTIVE,只不缓存@javax.persistence.Cacheable(false)标注的Entity
  • UNSPECIFIED,使用JavaEE服务器的默认设置

1)缓存的Retrieval Mode,用于在调用EntityManager.find()方法时,控制数据从缓存中读取还是从数据库中读取。

JPA提供了2种RetrievalMode:

  • javax.persistence.CacheRetrieveMode.USE

             优先读取缓存,如果缓存再没有再读取数据库

  • javax.persistence.CacheRetrieveMode.BYPASS

             无论何时都直接读取数据库


2)缓存的Store Mode,用于控制数据在缓存中的存储。

JPA提供了2种StoreMode:

  • javax.persistence. CacheStoreMode.BYPASS

             对数据库的任何操作,都不改变缓存

  • javax.persistence.CacheStoreMode.USE

             对数据库中数据的读写将导致在缓存中同步创建或修改数据

             如果缓存中已有该数据,则对该数据的后续读操作将不会刷新缓存

  • javax.persistence. CacheStoreMode.REFRESH

             对数据库中数据的读写将导致在缓存中同步创建或修改数据

             如果缓存中已有该数据,则对该数据的后续读操作仍然会刷新缓存


你可能感兴趣的:(java,数据库,orm,jpa,entity,ee)