EntityManager经常使用API

JPA实体状态分析java

实体状态详解docker

  • 瞬时状态:
  1. 实际上就是new了一个普通的JavaBean对象。
  • 托管状态:
  1. 1.当1.瞬时对象调用了管理器的persist()后,便可将通常的JavaBean作为了持久Bean,该Bean的任何属性改动都会牵涉到数据库记录的改动。
  2.  
  3. 2.一旦该记录flush到数据库以后,而且事务提交了,那么此对象不在持久化上下文中,即:变为了游离(没人管的孩子)状态了。
  4. 在游离状态的时候调用更新、刷新方法后,游离状态对象就变为了在持久化上下文的托管状态了。
  5.  
  6. 3.经过管理器的find方法,将实体从数据库查询出来后,该实体也就变为了托管形态。

    持久化状态:数据库

  1. 当处在托管状态的实体Bean被管理器flush了,那么就在极短暂的时间进入了持久化状态,事务提交以后,马上变为了游离状态。
  2. 您能够把持久化状态当作实实在在的数据库记录。
  • 游离状态:
  1. 游离状态就是提交到数据库后,事务commit后实体的状态,由于事务已经提交了,此时实体的属性任你如何改变,也不会同步到数据库,
  2. 由于游离是没人管的孩子,不在持久化上下文中。
  • 销毁对象:
  1. 通常要删除一个持久化对象的时候都是先find出来,以后调用remove方法删之,此时这个对象就是销毁对象,实际上就是瞬时对象的另外一种形态罢了。

EntityManager一些经常使用的API(包含query, insert, update, delete操做)缓存

1)get entity —— find() or getReference()服务器

  1. Person person = em.find(Person.class,1);
  • 当在数据库中没有找到记录时,getReference()和find()是有区别的,
    • find()方法会返回null,
    • 而getReference() 方法会抛出javax.persistence.EntityNotFoundException例外,
  • 调用getReference()方法,返回的其实并非实例对象,而是一个代理。当你要使用实体时,才会真正的调用查询语句来查询实例对象
  • 另外getReference()方法不保证 entity Bean已被初始化。
  • 若是传递进getReference()或find()方法的参数不是实体Bean,都会引起 IllegalArgumentException

2)insert —— persist()网络

  1. Person person = new Person();
  2. person.setName(name);
  3. //把数据保存进数据库中
  4. em.persist(person);
  • persist方法的:使对象由临时状态变为持久化状态
  • 若是传递进persist()方法的参数不是实体Bean,会引起IllegalArgumentException
  • 和hibernate的save()方法有些不一样:若是对象有id,则不能执行insert操做,会抛出异常

3)update —— 分2种状况
    状况1:当实体正在被容器管理时,你能够调用实体的set方法对数据进行修改,在容器决定flush时(这个由Container自行判断),更新的数据 才会同步到数据库,而不是在调用了set方法对数据进行修改后立刻同步到数据库。若是你但愿修改后的数据立刻同步到数据库,你能够调用EntityManager.flush()方法。session

  1. public void updatePerson() {
  2. try {
  3. Person person = em.find(Person.class, 1);
  4. person.setName("lihuoming"); //方法执行完后便可更新数据
  5. } catch (Exception e) {
  6. e.printStackTrace();
  7. }
  8. }


    状况2:在实体Bean已经脱离了EntityManager的管理时,你调用实体的set方法对数据进行修改是没法同步更改到数据库的。你必须调用 EntityManager.merge()方法。调用以后,在容器决定flush时(这个由container自行判断),更新的数据才会同步到数据 库。若是你但愿修改后的数据立刻同步到数据库,你能够调用EntityManager.flush()方法性能

  1. public boolean updatePerson(Person person) {
  2. try {
  3. em.merge(person);
  4. } catch (Exception e) {
  5. e.printStackTrace();
  6. return false;
  7. }
  8. return true;
  9. }

    下面的代码会调用上面的方法。由于下面的第二行代码把实体Bean 返回到了客户端,这时的实体Bean已经脱离了容器的管理,在客户端对实体Bean进行修改,最后把他返回给EJB 容器进行更新操做:编码

  1. PersonDAO persondao = (PersonDAO) ctx.lookup("PersonDAOBean/remote");
  2. Person person = persondao.getPersonByID(1); //此时的person 已经脱离容器的管理
  3. person.setName("张小艳");
  4. persondao.updatePerson(person);
  • merge 状况1:传入的对象没有id
  1. 在这种状况下,调用merge方法,将返回一个新的对象(有id),并对这个新的对象执行insert操做。
  • merge 状况2:传入的对象有id,entityManager的缓存中没有该对象,数据库中没有该记录:
  1. 在这种状况下,调用merge方法,将返回一个新的对象,并对该对象执行insert操做。
  2. 新对象的id是数据库中这条记录的id(好比自增加的id,而不是咱们本身传入的id。(其实和状况1的结果是同样的)
  • merge 状况3:传入的对象有id,entityManager的缓存没有该对象,数据库中有该记录
  1. 在这种状况下,调用merge方法,将会从数据库中查询对应的记录,生成新的对象,而后将咱们传入的对象复制到新的对象,最后执行update操做。 
  2. 简单来讲,就是更新操做
  • merge 状况4:传入的对象有id,entityManager的缓存有该对象
  1. 在这种状况下,调用merge方法,JPA会把传入的对象赋值到entityManager的缓存中的对象,而后对entityManager缓存中的对象执行update操做。
  2. (和状况3的结果同样)


4)Delete —— Remove().net

  1. Person person = em.find(Person.class, 2);
  2. //若是级联关系cascade=CascadeType.ALL,在删除person 时候,也会把级联对象删除。
  3. //把cascade属性设为cascade=CascadeType.REMOVE 有一样的效果。
  4. em.remove (person);
  • 若是传递进remove ()方法的参数不是实体Bean,会引起一个IllegalArgumentException
  • remove()方法不能移除游离对象,只能移除持久化对象
    1. Order order = new Order();
    2. order.setId(140);
    3. entityManager.remove(order);

    上面这段代码会抛出异常,由于order是咱们本身建立的对象,也就是游离对象。必须这样写:

     

    1. Order order = new Order();
    2. order = entityManager.find(Order.class, 140);
    3. entityManager.remove(order);

    这段代码中的order是从数据库中获取的,也就是持久化对象

  • hibernate的delete()方法,只要对象有Id,就能够删除

5)HPQL query —— createQuery()
除了使用find()或getReference()方法来得到Entity Bean以外,你还能够经过JPQL获得实体Bean。

  • 要执行JPQL语句,你必须经过EntityManager的createQuery()或createNamedQuery()方法建立一个Query 对象
  • // 执行查询语句
  1. Query query = em.createQuery("select p from Person p where p. name=’黎明’");
  2. List result = query.getResultList();
  3. Iterator iterator = result.iterator();
  4. while( iterator.hasNext() ){
  5. //处理Person
  6. }
  • // 执行更新语句
  1. Query query = em.createQuery("update Person as p set p.name =?1 where p. personid=?2");
  2. query.setParameter(1, “黎明”);
  3. query.setParameter(2, new Integer(1) );
  4. int result = query.executeUpdate(); //影响的记录数
  • // 执行删除语句
  1. Query query = em.createQuery("delete from Person");
  2. int result = query.executeUpdate(); //影响的记录数

6)SQL query —— createNaiveQuery()

  • 注意:该方法是针对SQL语句,而不是HPQL语句
  1. //咱们可让EJB3 Persistence 运行环境将列值直接填充入一个Entity 的实例,
  2. //并将实例做为结果返回.
  3. Query query = em.createNativeQuery("select * from person", Person.class);
  4. List result = query.getResultList();
  5. if (result!=null){
  6. Iterator iterator = result.iterator();
  7. while( iterator.hasNext() ){
  8. Person person= (Person)iterator.next();
  9. … ..
  10. }
  11. }
  • // 直接经过SQL 执行更新语句
  1. Query query = em.createNativeQuery("update person set age=age+2");
  2. query.executeUpdate();

7)Refresh entity —— refresh()

  1. Order order= entityManager.find(Order.class, 170);
  2. order= entityManager.find(Order.class, 170);
  • 运行以上代码,发现调用了两次find,可是只执行了一次select语句,这是缓存致使的。
  1. Order order= entityManager.find(Order.class, 170);
  2. entityManager.refresh(order);
  • 只调用了一次find方法,却执行了两次select语句,这是由于refresh方法会去查看缓存中的数据状态和数据库中是否一致,所以又执行了一次select语句
  • 若是你怀疑当前被管理的实体已经不是数据库中最新的数据,你能够经过refresh()方法刷新实体,容器会把数据库中的新值重写进实体。
  • 这种状况通常发 生在你获取了实体以后,有人更新了数据库中的记录,这时你须要获得最新的数据。
  • 固然你再次调用find()或getReference()方法也能够获得 最新数据,但这种作法并不优雅。
  1. Person person = em.find(Person.class, 2);
  2. //若是此时person 对应的记录在数据库中已经发生了改变,
  3. //能够经过refresh()方法获得最新数据。
  4. em.refresh (person);

8)Check entity是否在EntityManager管理当中 —— contains()

  • 判断一个实例是否属于当前持久上下文环境管理的实体
  • contains()方法使用一个实体做为参数,若是这个实体对象当前正被持久化内容管理,返回值为true,不然为false。
  • 若是传递的参数不是实体 Bean,将会引起一个IllegalArgumentException.
  1.  
  2. Person person = em.find(Person.class, 2);
  3. 。。。
  4. if (em.contains(person)){
  5. //正在被持久化内容管理
  6. }else{
  7. //已经不受持久化内容管理
  8. }


9)分离全部当前正在被管理的实体 —— clear()

  • 清除持久上下文环境,断开全部关联的实体。若是这时还有未提交的更新则会被撤消。
  • 在处理大量实体的时候,若是你不把已经处理过的实体从EntityManager中分离出来,将会消耗你大量的内存。
  • 调用EntityManager 的clear()方法后,全部正在被管理的实体将会从持久化内容中分离出来。
  • 有一点须要说明下,在事务没有提交前(事务默认在调用堆栈的最后提交,如:方 法的返回),若是调用clear()方法,以前对实体所做的任何改变将会掉失,
  • 因此建议你在调用clear()方法以前先调用flush()方法保存更 改

10)将实体的改变马上刷新到数据库中 —— flush()

  • 当EntityManager对象在一个session bean 中使用时,它是和服务器的事务上下文绑定的。
  • EntityManager在事务提交时而且同步它的内容。
  • 在一个session bean 中,服务器的事务默认地会在调用堆栈的最后提交(如:方法的返回)。
  1. 例子1:在方法返回时才提交事务
  2. public void updatePerson(Person person) {
  3. try {
  4. Person person = em.find(Person.class, 2);
  5. person.setName("lihuoming");
  6. em.merge(person);
  7. //后面还有众多修改操做
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }
  11. //更新将会在这个方法的末尾被提交和刷新到数据库中
  12. }
  • 为了只在当事务提交时才将改变动新到数据库中,容器将全部数据库操做集中到一个批处理中,这样就减小了代价昂贵的与数据库的交互。
  • 当你调用 persist( ), merge( )或remove( )这些方法时,更新并不会马上同步到数据库中,直到容器决定刷新到数据库中时才会执行,
  • 默认状况下,容器决定刷新是在“相关查询”执行前或事务提交时发 生,
  • 固然“相关查询”除find()和getreference()以外,这两个方法是不会引发容器触发刷新动做的,默认的刷新模式是能够改变的。


若是你须要在事务提交以前将更新刷新到数据库中,你能够直接地调用EntityManager.flush()方法。

这种状况下,你能够手工地来刷新数据 库以得到对数据库操做的最大控制。

  1. public void updatePerson(Person person) {
  2. try {
  3. Person person = em.find(Person.class, 2);
  4. person.setName("lihuoming");
  5. em.merge(person);
  6. em.flush();//手动将更新马上刷新进数据库
  7.  
  8. //后面还有众多修改操做
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. }
  12. }

11)改变实体管理器的Flush模式 —— setFlushMode()

  • setFlushMode()的Flush模式有2种类型:AUTO and COMMIT。AUTO为缺省模式。你能够改变他的值,以下:
  1. entityManager.setFlushMode(FlushModeType.COMMIT);
  • FlushModeType.AUTO:
  1. 刷新在查询语句执行前(除了find()和getreference()查询)或事务提交时才发生,
  2. 使用场合:在 大量更新数据的过程当中没有任何查询语句(除了find()和getreference()查询)的执行。
  • FlushModeType.COMMIT:
  1. 刷新只有在事务提交时才发生,
  2. 使用场合:在大量更新数据的过程当中存在查询语句(除了find()和 getreference()查询)的执行。
  • 其实上面两种模式最终反映的结果是:JDBC 驱动跟数据库交互的次数。
  1. JDBC 性能最大的增进是减小JDBC 驱动与数据库之间的网络通信。
  2. FlushModeType.COMMIT模式使更新只在一次的网络交互中完成,而FlushModeType.AUTO 模式可能须要屡次交互(触发了多少次Flush 就产生了多少次网络交互)

12)获取持久化实现者的引用 —— getDelegate()

  • 用过getDelegate()方法,你能够获取EntityManager持久化实现者的引用,
  • 如Jboss EJB3的持久化产品采用Hibernate,能够经过getDelegate()方法获取对他的访问,如:
  1. HibernateEntityManager manager = (HibernateEntityManager)em.getDelegate();
  • 得到对Hibernate的引用后,能够直接面对Hibernate进行编码,不过这种方法并不可取,强烈建议不要使用。

13)判断当前的实体管理器是不是打开状态--isOpen ()

14)返回资源层的事务对象。EntityTransaction实例能够用于开始和提交多个事务--getTransaction ()

15)大量数据分批提交

  1. 有的时候咱们须要循环保存数据,当保存大量数据的时候,
  2. 若是到最后才提交全部数据,那么数据库的负载可能会比较大。咱们能够这样作,每30个记录就提交(flush)一次。

代码以下(每到30条记录的时候就强制提交):

  1. public void updateBatch(List<Z> list) {
  2. for (int i = 0; i < list.size(); i++) {
  3. entityManager.merge(list.get(i)); //变成托管状态
  4. if (i % 30 == 0) {
  5. entityManager.flush(); //变成持久化状态
  6. entityManager.clear(); //变成游离状态
  7. }
  8. }
  9. }
  10.  
  11. public void saveBatch(List<Z> list) {
  12. for (int i = 0; i < list.size(); i++) {
  13. entityManager.persist(list.get(i)); //变成托管状态
  14. if (i % 30 == 0) {
  15. entityManager.flush(); //变成持久化状态
  16. entityManager.clear(); //变成游离状态
  17. }
  18. }
  19. }

    参考来源: http://blog.csdn.net/fobdddf/article/details/19479073

    参考来源: http://blog.csdn.net/dufufd/article/details/54408727

    参考来源:http://toknowme.iteye.com/blog/2235981

相关文章
相关标签/搜索