您的位置:首页 > 其它

JPA实体管理器

2015-08-27 18:11 218 查看



在JPA规范中,EntityManager是所有持久化操作的中枢。实体作为普通Java对象,只有在调用EntityManager将其持久化后,才会变成持久对象。

根据EntityManager对象的管理方式,有以下两种类型:

l 容器托管

容器托管的EntityManager对象最简单,不需要考虑EntityManager的连接和释放,以及事务的管理,这些操作都由容器来管理。容器托管的EntityManager对象必须在EJB容器中运行,而不能在web容器和JavaSE环境中运行。

l 应用托管

应用托管的EntityManager对象,需要手动管理EntityManager的连接和释放,以及事务管理。应用托管的EntityManager可以脱离EJB容器,而运行在web容器或JavaSE环境中。

1、EntityManagerFactory

在web容器或EJB容器中可以通过@PersistenceUnit来注入一个EntityManagerFactory对象,进而获取EntityManager对象;也可以直接通过@PersistenceContext来直接注入一个EntityManager对象。

在JavaSE项目中,可以通过Persistence来创建EntityManagerFactory对象,如下

EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa");

2、实体的状态

实体对象拥有以下4个状态,这些状态通过调用EntityManager接口发生迁移。

1. 新建状态

新创建的实体对象,尚未拥有持久化主键,没有和一个持久化上下文关联起来。

2. 托管状态

已经拥有持久化主键,并和持久化上下文建立了联系。

3. 游离状态

拥有持久化主键,但没有和持久化上下文建立联系。

4. 删除状态

拥有持久化主键,已经和持久化上下文建立联系,但已经从数据库中删除。

3、find

如果知道实体的主键,可以使用find方法来获得实体。方法的第一个参数为实体类,第二个参数为实体OID,即标准了@Id的值。

find方法返回指定OID的实体,如果这个实体存在于当前 的持久化上下文中,那么返回被缓存的对象;否则,从数据库中加载相关的持久化状态。如果数据库中不存在指定OID的记录,则返回null。

4、getReference

getReference方法与find相似,不同的是如果缓存中没有指定的实体,则会返回一个代理对象,并不会立即查询数据库。当第一次访问对象时,才会从数据库加载数据,若记录不存在则抛出EntityNotFoundException异常。

5、persist

persist方法用于将新创建的实体纳入EntityManager的管理,当执行flush操作后或事物提交时,实体的数据将被保存到数据库中。

该方法执行后,实体对象将转换为托管状态。如果实体对象已经处于托管住状态,则persist操作不会发生任何事情。如果为删除状态的实体对象,执行persist操作,则实体对象转换为托管状态。如果实体对象为游离状态,执行persist后抛出EntityExistsException,也有可能在flush操作或事物提交时抛出EntityExistsException或PersistenceException。

注意:如果实体与其他实体之间存在关联关系,并设置了级联保存,那么persist操作会传播到其它实体。

6、merge

merge方法用于处理实体的同步,及数据库插入或更新操作。因为实体Bean可以脱离EntityManager管理,当需要重新将游离态的实体纳入EntityManager的管理中,可以使用merge方法,使实体的数据能被同步回数据库。

对处于不同状态的实体,merge方法具有以下行为:

1) 新建状态

创建该实体的一个备份,并将这个备份纳入到EntityManager的管理中。

2) 托管状态

merge操作被忽略。

3) 删除状态

merge操作会导致IllegalArgumentException。

4) 游离状态

如果此时容器中已经存在相同主键的托管对象B,会把参数传进来的实体的内容复制到托管对象B,并返回B的引用;但参数引用的对象仍是游离态;

如果容器中不存在相同主键的托管对象,则创建该实体的一个备份B,并将B纳入到EntityManager的管理中,同时返回B的引用,当执行Flush操作时会把B的状态同步到数据库中。

注意:如果实体与其他实体之间存在关联关系,并设置了级联合并,那么merge操作会传播到其它实体。

7、remove

如果需要删除某个实体Bean,可以执行remove方法。对处于不同状态的实体,remove方法具有以下行为:

1) 新建状态:操作被忽略;

2) 托管状态:实体被删除;

3) 删除状态:操作被忽略;

4) 游离状态:导致IllegalArguementException。

注意:如果实体与其他实体之间存在关联关系,并设置了级联删除,那么remove操作会传播到其它实体。

8、refresh

如果怀疑当前托管对象存放的数据并非数据库中最新的数据,可以通过refresh发那个发来刷新实体对象。对处于不同状态的实体,refresh方法具有以下行为:

1) 新建状态:抛出IllegalArgumentException;

2) 托管状态:执行刷新操作;

3) 删除状态: 抛出IllegalArgumentException;

4) 游离状态: 抛出IllegalArgumentException;

注意:如果实体与其他实体之间存在关联关系,并设置了级联刷新,那么refresh操作会传播到其它实体。

9、contains

contains方法用来判断一个实体对象是否处于持久化上下文中。

10、clear

在处理大量实体时,如果不把已经处理过的实体从持久化上下文中分离出来,将会消耗大量的内存。clear方法将会使处于托管状态的对象,变为游离态。

注意:在事务没有提交前执行clear方法,之前对实体所做的任何修改将会丢失,建议在调用clear方法前,先执行flush方法保存更改。

11、flush

当执行persist、merge、remove或托管状态对象的setter方法时,实体的状态并不会立即同步到数据库中,知道执行flush方法时,才会将实体的状态同步到数据库中。目的是为了减少与数据库交互的次数,以提高性能。持久化上下文会将所有的操作集中到一个批处理中,并在某个时刻提交到数据库。

默认的flush模式是FlushModeType.AUTO,表示flush是在查询语句执行前或事务提交时才发生。“查询语句”指的是Query对象执行的查询,而不是find或getReference方法进行的查询。flush还有另外一种刷新模式——FlushModeType.COMMIT,它表示只有在事务提交时才执行flush操作。如果是容器管理事务,事务提交的时间为方法执行结束。总的来说AUTO模式比较智能,可以确定什么时候flush;但COMMIT模式更有效率,在一个事务中只发生一次flush操作,而AUTO模式可能会发生大于等于一次(当事务中一系列的更新操作中有查询语句时,则会多次执行flush)。为什么会存在AUTO模式呢,COMMIT模式不是很好吗?

由于COMMIT模式在事务提交时才执行flush操作,如果是容器管理事务,事务提交的时间为方法执行结束。若在事务内先执行更新操作,再执行查询操作(查询更新的对象),COMMIT模式并不能查询到更新的对象,而是查询到更新之前的记录。解决方法有:一是,在查询前强制执行flush方法;二是,采用AUTO模式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: