LazyInitializationException的四个解决方案–第2部分

本文从本教程的第1部分继续。

有状态EJB使用PersistenceContextType.EXTENDED进行负载收集

该方法只能应用于与Full JEE环境兼容的应用程序:将EJB与PersistenceContextType.EXTENDED一起使用。

检查下面的代码,DAO的样子:

package com.ejb;

import javax.ejb.Stateful;
import javax.persistence.*;

import com.model.Person;

@Stateful
public class SystemDAOStateful {
 @PersistenceContext(unitName = 'LazyPU', type=PersistenceContextType.EXTENDED)
 private EntityManager entityManager;

 public Person findByName(String name) {
  Query query = entityManager.createQuery('select p from Person p where name = :name');
  query.setParameter('name', name);

  Person result = null;
  try {
   result = (Person) query.getSingleResult();
  } catch (NoResultException e) {
   // no result found
  }

  return result;
 }
}
public class DataMB {
 // other methods and attributes

 @EJB
 private SystemDAOStateful daoStateful;

 public Person getPersonByStatefulEJB() {
  return daoStateful.findByName('Mark M.');
 }
}
<h:dataTable var='dog' value='#{dataMB.personByStatefulEJB.lazyDogs}'>
 <h:column>
  <f:facet name='header'>
   Dog name
  </f:facet>
  #{dog.name}
 </h:column>
</h:dataTable>

这种方法的优点和缺点:

优点

缺点

容器将控制数据库事务

仅适用于JEE

模型类别将不需要编辑

N + 1效应可能会发生

大量的有状态EJB可能会影响容器内存。

这种方法可能会产生N + 1效果,并且有状态EJB具有在其会话未到期或丢失参考之前不会被删除/销毁的特性。

警告 :在保留在Pool中的对象中保留对注入的EJB的引用不是一个好习惯。 JSF将创建一个ManagedBean池来更好地处理用户请求。 必要时,容器将增加或减少池中ManagedBean的数量。 在本文的代码中,假设如果容器在池中创建100个ManagedBeans实例,则服务器将在内存中容纳100个有状态EJB。 解决该问题的方法是对有状态EJB进行JNDI查找。

通过联接查询加载集合

该解决方案易于理解和应用。

请参见下面的代码:

public Person findByNameWithJoinFech(String name) {
  Query query = entityManager.createQuery('select p from Person p join fetch p.lazyDogs where p.name = :name');
  query.setParameter('name', name);

  Person result = null;
  try {
   result = (Person) query.getSingleResult();
  } catch (NoResultException e) {
   // no result found
  }

  return result;
 }
public Person getPersonByQuery() {
  return systemDAO.findByNameWithJoinFech('Mark M.');
 }
<h:dataTable var='dog' value='#{dataMB.personByQuery.lazyDogs}'>
  <h:column>
   <f:facet name='header'>
    Dog name
   </f:facet>
   #{dog.name}
  </h:column>
 </h:dataTable>

这种方法的优点和缺点:

优点

缺点

数据库中只会触发一个查询

每个访问的集合/惰性属性都需要一个查询

模型类别将不需要编辑

仅会带来所需的数据

N + 1效果不会发生

这种方法的缺点是需要新的查询来访问每个模型类集合/惰性属性。 如果只需要查询“ Person”狗,则需要特定查询。 假设我们需要查询“个人”电子邮件,则有必要进行其他查询。

这种方法可以应用于JSE和JEE。

EclipseLink和惰性集合初始化

关系的默认值为:

关系

@OneToOne

急于

@OneToMany

@多多

急于

@多多多

但是JPA Spec *指出:

EAGER策略是对持久性提供程序运行时的要求,必须热切地获取数据。 LAZY策略向持久性提供程序运行时提供了一个提示,即在首次访问数据时应延迟获取数据。 允许该实现急切地获取已为其指定LAZY策略提示的数据 特别是,懒惰获取可能仅适用于使用基于属性的访问的基本映射。

如您在上面的文本中看到的那样,JPA实现可能会忽略提示策略。 EclipseLink具有JEE行为和JSE其他行为。 您可以在这里看到每种行为: http : //wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#What_You_May_Need_to_Know_About_EclipseLink_JPA_Lazy_Loading

我们在互联网上可以发现有人说,即使是惰性集合,EclipseLink也会在实体加载时执行n + 1查询。 我们可以找到使用Glassfish和EJB的用户的这种行为。

在下面,您将看到一些在EclipseLink上正确使用延迟加载的提示:

* JSR-000220企业JavaBeans 3.0最终版本(持久性)9.1.18,并将重复与水獭JPA的关系。

结束!

我认为最好的解决方案是联接获取查询。 您可以根据自己的应用选择最佳解决方案

单击此处下载该帖子的源代码 。 如果要运行本文的代码,则需要创建一个名为LazyExceptionDB的数据库和JBoss模块。 附加到源代码的是Postgres模块。 如果您想了解如何设置数据源以及Postgres或MySQL模块,则可以在这里看到: 完整的WebApplication JSF EJB JPA JAAS

希望这篇文章对您有所帮助。

如果您有任何意见或疑问,请发表。

再见。

参考: uaiHebert博客上的JCG合作伙伴 Hebert Coelho 对LazyInitializationException的四种解决方案


翻译自: https://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值