Entity Identity 实体标识
一般采用单一值做为entity identity
采用compsite primary key时,必须单独建立一个表示主键的类-primary key class主键类。这样在实体上compsite primary key就可以用一个属性(primary key class类型)表示
持久化框架内部很多地方使用entity identity进行处理,因此primary key class要正确实现equals、hashCode方法
另外应用层需要注意,对persistence context中受管理的对象,不要修改主键值,否则持久化框架无法承诺带来的影响,因为persistence context只能基于entity identity标识实体身份
Accessor of Persistent Fields and Properties 持久化值域和属性的访问器
Persistent state(即需要持久化的fields或properties)的存取分2种类型:field-based和property-based
field-based时持久化框架直接存取instance variables,property-based时则通过getter、setter方法存取
使用property-based时,在setter、getter方法中可能包含业务逻辑,对于应用层而言,需要注意的是持久化框架从数据库加载数据,为实体属性赋值时,各属性的赋值顺序是无法承诺的,因此getter、setter中的业务逻辑需要注意这一点
另外使用property-based时如果还将属性声明为lazy-fetching,则应用层不应当访问相应的instance variable,因为持久化框架可能对setter、getter进行注入以实现lazy-fetching,直接访问instance variable可能获取不到值
对于集合类型,JPA规定必须使用java.util下面的Collection、Set、Map、List这几个接口,关于List、Set、Map、Bag的语义,参考这篇post
Persistence Context 持久化上下文
Persistence Context是持久化框架需要维护的一个中间容器,其中会存放受管理对象的副本,例如从数据库获取的实体对象,或者调用持久化框架保存过的对象等
主要作用有:缓存(例如NHibernate的一级缓存概念)、支持Flush操作、辅助实现实体以及属性的Dirty检查等
JPA将persistence context分为2种类型:PersistenceContextType.TRANSACTION和 PersistenceContextType.EXTENDED。TRANSACTION类型(默认类型)的persistence context生命周期与transaction scope一致,例如事务开始时为生命周期的开始阶段,事务提交或回滚时生命周期结束。EXTENDED类型的生命周期基本与EntityManager 一致,在EntityManager创建时开始,在EntityManager关闭时结束。实现Extended类型的persistence context时需要注意其生命周期可能跨越多个事务以及不在事务范围内的情况,伴随的是这些情况下对persistence context中实例对象生命周期以及相关操作的影响,例如version控制等
Entity Instance's Life Cycle 实例对象生命周期
实例对象的生命周期可以参考一下这篇post
实例对象的生命周期有4种状态:
New: 新创建的实例对象,没有identity值
Managed: 在持久化上下文中受管理的对象
Detached: 游离于持久化上下文之外的实例对象
Removed: 被删除的实例对象
JPA中详细定义了实例对象伴随着EntityManager的各种操作时,生命周期状态间的转换关系
JPA声明了entity instance life cycle的几个callback方法:PrePersist、PostPersist、PreRemove、PostRemove、 PreUpdate、PostUpdate、PostLoad,对其语义进行了比较详细的说明
Entity Relationships 实体关系
JPA定义了one-to-one、one-to-many、many-to-one、many-to-many 4种关系
Owning side, Inverse side 关系的所有方、反向方
在关联关系的2方之中,关系的所有者一方为owning side,另一方为inverse side。关系的所有者可以这样来理解,将所有者一方的实例删除后,这个2方关系的任何信息都彻底消失。假如逻辑上表A有一个外键,引用自表B的主键(所谓逻辑上是指数据库中并没有建立这个外键关系),如果将表B中某条数据b1删除,A、B间相应实例对象的关联关系可能并不会彻底消除,因为表A中可能还存在某数据a1引用了b1的主键值,因此与B对应的实体类就不是owning side了
因此拥有外键的一方就是owning side了,这个在one-to-one的关系中比较清晰;one-to-many、many-to-one中,many的一方为owning side;many-to-many中任何一方都可以作为owning side
Owning side、inverse side将作为cascade相关操作的依据之一
JPA详细定义了默认情况下对以下一些映射的处理方式:
双向one-to-one;双向one-to-many、many-to-one;单向single-valued(单向one-to-one、 many-to-one);双向many-to-many;单向multi-valued(单向one-to-many、many-to-many)
Inheritance 继承
Inheritance Mapping Strategies包括:
Single table per class hierarchy,使用一个discriminator column区别子类,优点是很好的支持多态关系、查询,缺点是子类独有的字段需要允许为null
Table per concrete entity class,缺点是不好支持多态关系,通常需要对各子类分别使用单独的SQL或者使用UNION语句
Joined subclass,与table per concrete entity class区别是,将公共属性的superclass使用一个表存储,这种策略也能较好的支持多态关系,缺点是需要多个JOIN关系
详细参考这篇post
Optimistic Locking and Concurrency 乐观锁及并发控制
JPA默认应用层将使用乐观锁机制
使用乐观锁时entity必须声明一个version属性,该字段的值由持久化框架自动维护,应用层不能修改。持久化框架可以引入其它机制实现乐观锁检查,或者实现更细粒度的乐观锁控制,JPA不做要求
JPA的乐观锁机制是基于数据行的
JPA中声明了Lock Mode,可以实现悲观锁效果,至于实现方式不作具体要求,只要确保不存在P1: dirty read、P2: non-repeatable read就行
LockModeType有READ和WRITE 2种
对于WRITE模式,在isolation level为read commited情况下数据库可以确保不会出现P1、P2两种状况
READ模式一般使用数据库的锁实现,用它实现悲观锁效果
Query Language 查询语言
类SQL的语法,但是带上了较明显的对象特征
声明了SELECT、UPDATE、DELETE 3种语句
用简单的例子浏览一下大致特性
1. 使用实体间的关联关系