有状态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上正确使用延迟加载的提示:
- http://stackoverflow.com/questions/8490532/eclipselink-lazy-loading
- http://stackoverflow.com/questions/3932623/eclipselink-dont-fetch-some-fields-by-default
- https://forums.oracle.com/forums/thread.jspa?messageID=1706796
* 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