EntityManager.getReference()致使的懒加载问题(Lazy)

为了便与搜索直接把错误放出来: org.hibernate.LazyInitializationException: could not initialize proxy - no Session   。html

转自:http://blog.sina.com.cn/s/blog_605f5b4f0100hfzz.htmljava

因为EntityManager.getReference()致使的懒加载问题。数据库

先说相同点

    这两个方法都接受实体的 class和表明实体主键的对象做为参数。因为它们使用了Java泛型方法,无需任何显示的类型转换便可得到特定类型的实体对象。其中,在primaryKey上面广泛使用了java5的autoboxing(自动装箱)的特性。

    再者,就是二者都会在EntityManager关闭的状况下抛出IllegalStateException - if this EntityManager has been closed. 在传入的第一个参数不是实体或者第二个参数不是一个有效的主键的状况下抛出

IlegalArgumentException - if the first argument does not denote an entity type or the second argument is not a valid type for that entity's primary key

 

 

不一样点:

    find()返回指定OID的实体,若是这个实体存在于当前的persistence context中,那么返回值是被缓存的对象;不然会建立一个新的实体,并从数据库中加载相关的持久状态。若是数据库不存在指定的OID的记录,那么find()方法返回null。

    getReference()方法和find()类似。不一样的是:若是缓存中没有指定的实体,EntityManager会建立一个新的实体,可是不会当即访问数据库来加载持久状态,而是在第一次访问某个属性的时候才加载。此外,getReference()方法不返回null,若是数据库找不到相应的实体,这个方法会抛出javax.persistence.EntityNotFoundException。

EntityNotFoundException - if the entity state cannot be accessed
某些场合下使用getReference()方法能够避免从数据库加载持久状态的性能开销。

 

   *这里要着重提出的是两句话(重点):

   若是缓存中没有指定的实体,EntityManager会建立一个新的实体,可是不会当即访问数据库来加载持久状态,而是在第一次访问某个属性的时候才加载。

   好比,em.find()返回的实体,咱们就能够对它进行各类操做,而若对em.getReference()返回的实体,因为不会当即访问数据库来加载持久状态,对它进行的操做极可能就会出现Exception,好比在对它返回的实体作getter操做时,因为EntityManager对此采用延时加载,就会抛出org.hibernate.lazyinitializationexception could not initialize proxy no session

   所以将一个新的实体传递给事务的时候一般使用find()方法,而当不链接数据库,不使用getter方法,即便用setter方法改变状态时才使用getReference()方法。(这是因为getReference返回是一个Proxy实体,即没有加载持久状态)

 

   某些场合下使用getReference()方法能够避免从数据库加载持久状态的性能开销。

    这也彻底是因为getReference返回是一个Proxy实体.

    好比一个简单的update操做,先使用find()获取实体,然后使用实体的setter方法;或者是getReference()方法,然后使用实体的setter方法。

    对于前者JPA调用的SQL:select ****,然后才是update ****

    对于后者:仅为update *****

 

又如:

操做                                                                            执行的SQL

em.remove(em.getReference(Person.class,1))         delete from Person where personid = 1


em.remove(em.find(Person.class,1))                 select * from Person where personid =1

                                                   delete from Person where personid =1

 

   由此能够看出,find()作了一次select的操做,而getReference并无作有关数据库的操做,而是返回一个代理,这样它就减小了链接数据库和从数据库加载持久状态的开销。
相关文章
相关标签/搜索