在ORM的概念大行其道之际,JavaEE平台也不得不做出适当调整,直接在平台层提供了对象/关系映射机制JPA,并结合了其重要的Entity JavaBean。JPA概括起来包括如下3个部分:
JPA 中的Entity是一种可持久化的域对象。一个Entity类对应关系数据库中的一张表,一个Entity实例对应关系数据库中的表的一行记录。
一个Entity类的定义,需要遵守如下规则:
1)持久化字段
Entity类中的可持久化的类变量也被称为持久化字段。持久化字段的持久化标注是定义在类变量上的。通常,持久化字段将被存储到对应的数据库中,除非以下情况:
持久化属性的持久化标注是定义在类变量的getter方法上的。持久化属性都必须拥有getter/setter方法。如果类变量被如下定义,则不能在该类变量的getter方法上设置持久化标注,即这样的类变量不可能同时是持久化属性:
2. Entity Relationship
Entity和Entity之间的关系称为Entity Relationship,Entity关系的表示是通过Entity类中的关系字段或关系属性。Entity关系的类型(用以修饰关系字段或关系属性的标注)如下:
OneToMany
ManyToOne
1)Entity关系的方向性
Entity关系具有方向性,一个Entity关系所涉及的双方Entity,必然有一个owning方,另外还可以有一个inverse方。
Entity关系的定义可以是单向的,也可以是双向的:
拥有标注的这个Entity被称为关系的owning方(对应数据库的表中有外键)
其中一个Entity是关系的owning方,另一个Entity是关系的inverse方(标注中带有mappedBy)。
注意:
在
OneToOne
的关系中,对应数据库的表中有外键的是
owning
方;
在OneToMany
或
ManyToOne
的关系中,多方必须是
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标注。具体的映射策略如下:
@javax.persistence.Inheritance(strategy=”javax.persistence.InheritanceType.SINGLE_TABLE”)
@javax.persistence.Inheritance(strategy=”javax.persistence.InheritanceType.TABLE_PER_CLASS”)
@javax.persistence.Inheritance(strategy=”javax.persistence.InheritanceType.JOINED”)
4. 对Entity的管理EntityManager
javax.persistence.EntityManager对象负责管理位于同一数据库中的所有Entity。
一个EntityManager对象就对应一个持久化上下文(persistencecontext),即一个特定的数据存储,所有该数据存储中的Entity实例都由对应的EntityManager对象管理。事实上,持久化上下文实现对Entity实例的具体操作,而javax.persistence.EntityManager接口中定义的方法只是用于与持久化上下文交互。
在JTA事务中往往要访问持久化上下文,这时只要将该持久化上下文对应的EntityManager注入到应用中即可。对于JavaEE容器管理的EntityManager,无需在应用类之间传递EntityManager,JavaEE容器负责EntityManager的生命周期管理,并且在整个JTA事务中可用。
@javax.persistence.PersistenceContext EntityManager em;
由于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种状态:
Entity实例中的数据与数据库中数据进行同步的发生:
6. 对Entity的查询
JPA提供如下2种查询Entity的方法:
查询结果需要进行类型转换
类型安全
执行性能高
编程复杂
7. JPA的锁机制
数据库的表中有version列(Entity类中的字段或属性使用@javax.persistence.Version标注),应用只能读取不能修改。
事务提交时申请short-termlock,失败则抛出javax.persistence.OptimisticLockException异常并回滚事务。
事务在创建的时候就开始持有long-termlock,直至事务结束。
JPA提供的锁模式:
8. JPA的二级缓存
二级缓存是在JavaEE服务器上对一个持久化上下文中Entity的本地存储,对于应用来说是透明的。
JPA提供的缓存模式:
1)缓存的Retrieval Mode,用于在调用EntityManager.find()方法时,控制数据从缓存中读取还是从数据库中读取。
JPA提供了2种RetrievalMode:
优先读取缓存,如果缓存再没有再读取数据库
无论何时都直接读取数据库
2)缓存的Store Mode,用于控制数据在缓存中的存储。
JPA提供了2种StoreMode:
对数据库的任何操作,都不改变缓存
对数据库中数据的读写将导致在缓存中同步创建或修改数据
如果缓存中已有该数据,则对该数据的后续读操作将不会刷新缓存
对数据库中数据的读写将导致在缓存中同步创建或修改数据
如果缓存中已有该数据,则对该数据的后续读操作仍然会刷新缓存