JPA实体管理器
2015-08-27 18:11
218 查看
根据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模式。
相关文章推荐
- 'WSGIRequest' object has no attribute 'user'
- Django-1.8.3新建一个简单的News app——01初探urls views
- iOS js oc相互调用(JavaScriptCore)(二)
- 蒙板缓存和蒙板测试
- FreeMarker 那一眸我看懂了你
- C++ string 与其他类型的转换
- 线段树经典操作模板(单点更新,替换;区间更新,替换;区间求和求最值)
- hive-学习笔记
- 07-30 数组
- [源码]简易投票系统
- 【Qt】QThread::moveToThread
- SPFA 算法详解
- JPA实体关系映射
- centos7 安装mysql
- Jquery 的遍历,祖先、后代、同胞以及其过滤
- B. Pasha and Tea
- html 添加视频
- 黑马程序员--对象的存储细节
- const, static, extern, typedef
- Scheme 语言概要(下)