JPA(Java Persistence API,Java持久化API),定义了对象-关系映射(ORM)以及实体对象持久化的标准接口。
JPA是JSR-220(EJB3.0)规范的一部分,在JSR-220中规定实体对象(EntityBean)由JPA进行支持。
所以JPA不局限于EJB3.0,而是作为POJO持久化的标准规范,可以脱离容器独立运行,开发和测试更加方便。
下面通过一张图来看一下JPA的基本概念。然后再做简要分析。
注:不是真正意义的UML图啊,只是画着方便就用rose了。
一、EntityManager,EntityManagerFactory,PersistenceContext三者的关系
1、EntityManager和EntityManagerFactory
EntityManager称为实体管理器,它由EntityManagerFactory所创建。EntityManagerFactory,作为EntityManager的工厂,包含有当前O-R映射的元数据信息,每个EntityManagerFactory,可称为一个持久化单元(PersistenceUnit),每个持久化单元可认为是一个数据源的映射(所谓数据源,可理解为一个数据库,我们可以在应用服务器中配置多个数据源,同时使用不同的PersistenceUnit来映射这些数据源,从而能够很方便的实现跨越多个数据库之间的事务操作!)
2、EntityManager和PersistenceContext
PersistenceContext,称为持久化上下文,它一般包含有当前事务范围内的,被管理的实体对象(Entity)的数据。每个EntityManager,都会跟一个PersistenceContext相关联。PersistenceContext中存储的是实体对象的数据,而关系数据库中存储的是记录。
EntityManager正是维护这种OR映射的中间者,它可以把数据从数据库中加载到PersistenceContext中,也可以把数据从PersistenceContext中持久化到数据库。
EntityManager是应用程序操纵持久化数据的接口,EntityManager的接口方法有:
Persist、merge、remove、refresh、flush,
通过这些接口操纵PersistenceContext中的实体对象与数据库数据之间的同步!
这里又牵扯到一个实体对象的生命周期的概念
(1)几种状态
New–即未有id值,尚未跟persistence context建立关联的对象
Managed–有id值,已跟persistence context建立了关联
Detached–有id值,但没有(或不再)跟persistence context建立关联
Removed–有id值,而且跟persistence context尚有关联,但已准备好要从数据库中把它删除。
(2)与EntityManager接口的关系
小小结:EntityManager的作用与hibernate session类似。为了能够在一个请求周期中使用同一个session对象,在hibernate的解决方案中,提出了currentSession的概念,hibernate中的current session,可以跟JTA事务绑定,也可以跟当前线程绑定。在hibernate中,session管理着所有的持久化对象的数据。而在EJB3中,EntityManager管理着PersistenceContext,PersistenceContext正是被管理的持久化对象的集合。
二、EntityManager的管理方式分为两种:
1、容器管理的EntityManager– 通过PersistenceContext注入EntityManager对象,或通过jndi查询到EntityManager
定义方式:
@PersistenceContext(name="test")
private EntityManager em;
容器管理的EntityManager ,它所管理的PersistenceContext的生命周期由PersistenceContextType来配置
(1)Transaction-Scoped PersistenceContext – 由容器创建,随着Transaction而传播,随着Transaction的完成而销毁,对应用程序本身来说,它对persitence context的创建、销毁一无所知,完全自动和透明。当entity manager的方法被调用的时候,如果在当前JTA事务中还没有persistence context,那么将启动一个新的persistence context,并将它跟当前的JTA事务关联。
定义方式:
@PersistenceContext(unitName="myunit", type=PersistenceContextType.TRANSACTION)
private EntityManager em;
如:在Java EE环境下,一个JTA事务通常会横跨多个组件的调用(比如多个EJB组件的方法调用)。这些组件需要能够在单个事务范围内访问到同样的Persistence Context。为了满足这种情况的需要,当EntityManager被注入或通过jndi被查询的时候,它的Persistence Context将会在当前事务范围内自动传播,引用到同一个Persistence unit的EntityManager将使用同样的Persistence Context。这可以避免在不同的组件之间传递EntityManager引用。
(2)Extended-Scoped PersistenceContext – 用于Stateful Session Bean,跨越多个Transaction,随着Stateful Session Bean的销毁而销毁,通常,这可以通过调用一个在stateful session bean中被注解定义为@Remove的方法来结束一个stateful session bean的生命周期。
@PersistenceContext(unitName="test", type=PersistenceContextType.EXTENDED)
private EntityManager em;
2、应用管理的EntityManager– 通过PersistenceUnit注入EntityManagerFactory对象
定义方式:
@PersistenceUnit(unitName="test")
private EntityManagerFactory factory;
应用程序自身需要独立访问Persistence Context。即每次创建一个EntityManager都会迫使创建一个新的Persistence Context。这些Persistence Context即使在同一个事务范围内也不会跟其它EntityManager共享!这个创建过程可以由EntityManagerFactory的createEntityManager方法来创建,通过entityManager.close() / isOpen()方法来管理entityManager及其对应的persistence context.。这被称为应用管理的实体管理器(application-managed entity manager)。
定义方式:
@PersistenceUnit(unitName="test")
private EntityManagerFactory factory;
public void addStudent(String name) {
EntityManager em = factory.createEntityManager();
三、事务实现
EntityManager底层的事务实现可以使用JTA或RESOURCE_LOCAL类型的事务控制策略。
1、JTA和RESOURCE_LOCAL的区别
(1)JTA一般在容器环境中使用,而RESOURCE_LOCAL一般在J2SE的环境下使用。
在J2SE的环境下,由应用程序自身来创建EntityManagerFactory,并由EntityManagerFactory创建EntityManager,通过EntityManager.getTransaction.begin()方法来开启事务,commit()方法提交事务等等,这种方式就是RESOURCE_LOCAL的基本使用方法。
Persistence.XML配置示例:
<persistence-unit name="test" transaction-type="JTA">
JTA常在容器环境下使用,也就是使用JTA类型的EntityManager,这样,EntityManager的调用都是在一个外部的JTA事务环境下进行的,不用手动开启,提交事务等
Persistence.XML配置示例:
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
(2)Container-Managed EntityManager必须是JTA类型的EntityManager,而Application-Managed EntityManager则既可以是JTA类型的EntityManager,也可以是RESOURCE_LOCAL类型的EntityManager。
2、JTA事务与普通JDBC事务的区别
(1)JDBC事务,一般由数据库本身来执行提交或回滚操作(单阶段提交)。所有数据库都有自己的事务管理器,管理执行的日志,这些管理器只能处理其自身的事务,称为本地事务。
(2)JTA支持多个数据源,站在更高的角度上,提供一个“事务处理监听器(TPM)”来管理和协调这些数据源之间的事务操作,它必须执行两阶段提交协议(2PC)。
1)准备阶段-TPM向所有RM(资源管理器,即数据库)确认状态,是否可以提交或回滚。
2)提交阶段-TPM确认提交之后,向所有RM发出提交指令或回滚指令
TPM本身会维护事务日志,以保证持久性或灾难恢复等。