LazyInitializationException的四种解决方案–第1部分

在今天的帖子中,我们将讨论常见的LazyInitializationException错误。 我们将看到四种避免该错误的方法,以及每种方法的优缺点。在本文的最后,我们将讨论EclipseLink如何处理该异常。

为了看到LazyInitializationException错误并进行处理,我们将使用带有EJB 3的应用程序JSF 2。

帖子主题:

  • 了解问题后,为什么会发生LazyInitializationException?
  • 通过注释加载集合
  • 通过View中的Open Session加载收集(View中的事务)
  • 使用PersistenceContextType.EXTENDED的有状态EJB加载收集
  • 通过联接查询加载集合
  • EclipseLink和惰性集合初始化

在本文的结尾,您将找到要下载的源代码。

注意 :在本文中,我们将找到一个简单的代码,该代码不适用设计模式。 本文的重点是展示LazyInitializationException的解决方案。

您将在这里找到的解决方案适用于Web技术,例如带Struts的JSP,带VRaptor的JSP,带Servlet的JSP,带其他功能的JSF。

模型类

在今天的帖子中,我们将使用“人与狗”类:

package com.model;import javax.persistence.*;@Entity
public class Dog {@Id@GeneratedValue(strategy = GenerationType.AUTO)private int id;private String name;public Dog() {}public Dog(String name) {this.name = name;}//get and set
}
package com.model;import java.util.*;import javax.persistence.*;@Entity
public class Person {@Id@GeneratedValue(strategy = GenerationType.AUTO)private int id;private String name;@OneToMany@JoinTable(name = 'person_has_lazy_dogs')private List<Dog> lazyDogs;public Person() {}public Person(String name) {this.name = name;}// get and set
}

注意,通过这两个类,我们将能够创建LazyInitializationException。 我们有一个带狗名单的人类。

我们还将使用一个类来处理数据库操作(EJB DAO),并使用ManagedBean来帮助我们创建错误并进行处理:

package com.ejb;import java.util.List;import javax.ejb.*;
import javax.persistence.*;import com.model.*;@Stateless
public class SystemDAO {@PersistenceContext(unitName = 'LazyPU')private EntityManager entityManager;private void saveDogs(List<Dog> dogs) {for (Dog dog : dogs) {entityManager.persist(dog);}}public void savePerson(Person person) {saveDogs(person.getLazyDogs());saveDogs(person.getEagerDogs());entityManager.persist(person);}// you could use the entityManager.find() method alsopublic 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;}
}
package com.mb;import javax.ejb.EJB;
import javax.faces.bean.*;import com.ejb.SystemDAO;
import com.model.*;@ManagedBean
@RequestScoped
public class DataMB {@EJBprivate SystemDAO systemDAO;private Person person;public Person getPerson() {return systemDAO.findByName('Mark M.');}
}

为什么会发生LazyInitializationException?

Person类具有一个Dog列表。 显示人员数据的最简单,最胖的方法是使用entityManager.find()方法并遍历页面(xhtml)中的集合。

我们想要的只是让代码波纹管做到这一点……

// you could use the entityManager.find() method alsopublic 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 Person getPerson() {return systemDAO.findByName('Mark M.');}
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN''http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml'xmlns:f='http://java.sun.com/jsf/core'xmlns:h='http://java.sun.com/jsf/html'xmlns:ui='http://java.sun.com/jsf/facelets'>
<h:head></h:head>
<h:body><h:form><h:dataTable var='dog' value='#{dataMB.personByQuery.lazyDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column></h:dataTable></h:form>
</h:body>
</html>

注意,在上面的代码中,我们要做的就是在数据库中找到一个人并将其狗显示给用户。 如果您尝试使用上面的代码访问该页面,则会看到以下异常:

[javax.enterprise.resource.webcontainer.jsf.application] (http–127.0.0.1-8080-2) Error Rendering View[/getLazyException.xhtml]: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.model.Person.lazyDogs, no session or session was closed                  at org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationException(AbstractPersistentCollection.java:393) 
[hibernate-core-4.0.1.Final.jar:4.0.1.Final]at org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationExceptionIfNotConnected
(AbstractPersistentCollection.java:385) [
hibernate-core-4.0.1.Final.jar:4.0.1.Final]at org.hibernate.collection.internal.AbstractPersistentCollection.
readSize(AbstractPersistentCollection.java:125) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]

为了更好地理解此错误,让我们看看JPA / Hibernate如何处理这种关系。

每次我们在数据库中进行查询时,JPA都会带入该类的所有信息。 这个规则的例外是当我们谈论列表(集合)时。 我们拥有一个公告对象的图像,其中包含70,000封将接收此公告的电子邮件列表。 如果您只想在屏幕上向用户显示公告名称,请想象一下,如果将70,000封电子邮件加载了该名称,JPA的工作就可以了。

JPA为类属性创建了一种名为“延迟加载”的技术。 我们可以通过以下方式定义延迟加载:“仅在需要时才从数据库加载所需的信息”。

注意,在上面的代码中,数据库查询将返回一个Person对象。 当您访问lazyDogs集合时,容器将注意到lazyDogs集合是一个lazy属性,它将“询问” JPA以从数据库加载该集合。

在执行查询的那一刻( 将带来lazyDogs集合 ),将发生异常。 当JPA / Hibernate尝试访问数据库以获取此惰性信息时,JPA将注意到没有打开的集合。 这就是为什么发生异常(缺少打开的数据库连接)的原因。

默认情况下,每个以@Many结尾的关系都会被延迟加载:@OneToMany和@ManyToMany。 默认情况下,将急切加载以@One结尾的每个关系:@ManyToOne和@OneToOne。 如果要设置延迟加载的基本字段(例如,字符串名称),请执行:@Basic(fetch = FetchType.LAZY)。

如果开发人员未将每个基本字段(例如,String,int,double)放在类中,我们将立即加载它们。

关于默认值的一个有趣主题是,对于同一批注,您可能会发现每个JPA实现(EclipseLink,Hibernate,OpenJPA)具有不同的行为。 我们将在稍后讨论。

通过注释加载集合

加载对象时,最简单,最胖的方法是通过注释添加惰性列表。 但这永远不是最好的方法

在下面的代码中,我们将介绍如何通过注释热切地加载集合:

@OneToMany(fetch = FetchType.EAGER)
@JoinTable(name = 'person_has_eager_dogs')
private List<Dog> eagerDogs;
<h:dataTable var='dog' value='#{dataMB.person.eagerDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column>
</h:dataTable>

这种方法的优点和缺点:

优点

缺点

易于设置

如果该类具有多个集合,则这将不利于服务器性能

该列表将始终与加载的对象一起提供

如果只想显示名称或年龄之类的基本类属性,则将所有配置为EAGER的集合加载名称和年龄

如果EAGER集合只有几个项目,则此方法将是一个很好的选择。 如果此人只有2条,3条狗,则您的系统将能够非常轻松地处理它。 如果稍后“ Persons狗”收集开始确实增长很多,那么这对服务器性能将不会有好处。

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

通过View中的Open Session加载收集(View中的事务)

在视图中打开会话(或在视图中打开事务)是一种设计模式,您将使数据库连接保持打开状态,直到用户请求结束。 当应用程序访问一个惰性集合时,Hibernate / JPA会进行数据库查询而不会出现问题,不会引发任何异常。

当将此设计模式应用于Web应用程序时,将使用实现Filter的类,该类将接收所有用户请求。 此设计模式非常容易应用,并且有两个基本操作:打开数据库连接和关闭数据库连接。

您将需要编辑“ web.xml ”并添加过滤器配置。 在下面检查我们的代码如何:

<filter><filter-name>ConnectionFilter</filter-name><filter-class>com.filter.ConnectionFilter</filter-class></filter><filter-mapping><filter-name>ConnectionFilter</filter-name><url-pattern>/faces/*</url-pattern></filter-mapping>
package com.filter;import java.io.IOException;import javax.annotation.Resource;
import javax.servlet.*;
import javax.transaction.UserTransaction;public class ConnectionFilter implements Filter {@Overridepublic void destroy() {}@Resourceprivate UserTransaction utx;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {try {utx.begin();chain.doFilter(request, response);utx.commit();} catch (Exception e) {e.printStackTrace();}}@Overridepublic void init(FilterConfig arg0) throws ServletException {}
}
<h:dataTable var='dog' value='#{dataMB.person.lazyDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column>
</h:dataTable>

这种方法的优点和缺点:

优点

缺点

模型类别将不需要编辑

所有交易必须在过滤器类中处理

开发人员必须对数据库事务错误非常谨慎。 可以通过ManagedBean / Servlet发送成功消息,但是当数据库提交事务时,可能会发生错误。

可能会发生N + 1效应(如下所示)

这种方法的主要问题是N + 1效应。 当该方法将一个人返回到用户页面时,该页面将迭代dogs集合。 当页面访问惰性集合时,将触发新的数据库查询以显示狗的惰性列表。 想象一下,如果狗有狗的集合,那么狗就是孩子。 为了加载狗子列表,将触发其他数据库查询。 但是,如果孩子有其他孩子,那么JPA再次会触发一个新的数据库查询……然后就可以了……

这是这种方法的主要问题。 一个查询几乎可以创建无限多个其他查询。

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

继续本教程的第二部分 。

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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux驱动

jeffies hz xtime 每秒钟系统时钟节拍数 prco < 内核内存视窗 include/linux/list.h < 内核的数据结构&#xff0c;链表 workques_struct 工作队列转载于:https://www.cnblogs.com/asreg/p/7148606.html

java 条码识别_条码识别示例代码

package api.jisuapi.barcode;import api.util.HttpUtil;import net.sf.json.JSONArray;import net.sf.json.JSONObject;public class Read {public static final String APPKEY "your_appkey_here";// 你的appkeypublic static final String URL "https://ap…

终极JPA查询和技巧列表–第2部分

这一部分是该系列文章的第一部分 。 JPA&#xff1a;NamedQuery&#xff0c;使用日期查询&#xff0c;有关getSingleResult方法的警告 为了避免重复查询代码&#xff0c;提高性能并简化维护查询&#xff0c;我们可以使用NamedQueries。 NamedQuery使用JPQL作为语法&#xff0c…

设置UITableView设置contentsize

由于UITableView是继承自UIScrollView的&#xff0c;所以他是可以设置contentsize的。 但是&#xff0c;我在试验的过程中&#xff0c;初始化UITableView实例后&#xff0c;直接设置它的contentsize是不起作用&#xff0c;在搜寻相关资料得知&#xff0c;UITableView会自动设置…

java 线程什么时候结束_java线程什么时候让出cpu?

Thread.sleep();sleep就是正在执行的线程主动让出cpu&#xff0c;cpu去执行其他线程&#xff0c;在sleep指定的时间过后&#xff0c;cpu才会回到这个线程上继续往下执行&#xff0c;如果当前线程进入了同步锁&#xff0c;sleep方法并不会释放锁&#xff0c;即使当前线程使用sle…

Hibernate配置方式

Hibernate配置方式 Hibernate给人的感受是灵活的&#xff0c;要达到同一个目的&#xff0c;我们可以使用几种不同的办法。就拿Hibernate配置来说&#xff0c;常用的有如下三种方式&#xff0c;任选其一。 在 hibernate.cfg.xml 中加入元素 <property>、<mapping>&a…

js中 javascript:void(0) 用法详解

javascript:void(0)表示不做任何动作。如&#xff1a; 复制代码代码如下:<a href"javascript:void(0);" οnclick"alert(ok);"></a> 这里表示这个链接不做跳转动作&#xff0c;执行onClick事件。 我想使用过ajax的都常见这样的代码&#xff1…

带有ActiveMQ的JMS

带有ActiveMQ的JMS JMS是Java Message Service的缩写&#xff0c;它提供了一种以松散耦合&#xff0c;灵活的方式集成应用程序的机制。 JMS以存储和转发的方式跨应用程序异步传递数据。 应用程序通过充当中介的MOM&#xff08;面向消息的中间件&#xff09;进行通信&#xff0c…

矩阵分解 java_使用矩阵分解为推荐系统

矩阵分解假设“潜在因素”&#xff0c;例如对用户的意大利食物的偏好和项目食物的意外性与矩阵中的评级有关 .因此&#xff0c;整个问题类型转变为矩阵重构问题&#xff0c;存在许多不同的解决方案 . 一个简单的&#xff0c;可能很慢的解决方案是(除了ALS和其他一些矩阵重建的可…

用户故事排球教练助手

计划&#xff1a;估计这个任务需要一周时间 需求分析&#xff1a;作为一名排球教练助手&#xff0c;我需要了解每场每位队员的技术动作&#xff0c;每场比赛每位队员的得分情况&#xff0c;以便教练更好的了解到每位队员的发挥情况和特长。 设计文档&#xff1a;用户进入此界面…

TMS320DM642学习----第一篇(硬件连接)

DSP设备型号&#xff1a;SEED-DTK-VPM642&#xff08;目前实验室用途&#xff1a;视频处理&#xff0c;图像处理方向&#xff0c;预计搭载目标跟踪以及云台防抖等算法&#xff09; 官网链接&#xff1a;http://www.seeddsp.com/index.php/Home/Product/detail/name/1/id/174.ht…

字符串内存内部

本文基于我对StackOverflow的回答 。 我正在尝试解释String类如何存储文本&#xff0c;内部存储和常量池如何工作。 这里要理解的要点是String Java对象与其内容– private value字段下的char[]之间的区别。 String基本上是char[]数组的包装器&#xff0c;将其封装并使其无法修…

关于inline-block 元素之间为何会产生间隔

关于inline-block 元素之间为何会产生间隔 现象&#xff1a; <body><input type"text"><input type"text"> </body> 在浏览器中的表现&#xff1a; 实时上不仅仅是 inline-block 会导致这种现象。 inline 也会导致。 那问题来了&a…

java 入参 是 枚举_java 枚举 参数传递

展开全部这样做是不行的&#xff0c;原因是&#xff1a;Java中的对象实例化都是在堆中&#xff0c;如果是普通的类实例变量&#xff0c;比如在方法636f707962616964757a686964616f313333376166371中定义的普通类实例变量&#xff0c;传到了方法2中&#xff0c;由于方法1和方法2…

loadView的使用总结

一、loadView 1. loadView什么时候被调用&#xff1f; 每次访问UIViewController的view&#xff08;如 controller.view、self.view&#xff09;并且view为nil&#xff0c;loadView方法就会被调用 2. 有什么作用 loadView 方法是用来负责创建UIViewController的view 3. 默认实…

数据库备份 java jar_Java实现数据库备份并利用ant导入SQL脚本

​数据备份对于经常在运维部署方面的工作者来说&#xff0c;是一件相对简单的事情&#xff0c;都可以通过某一个SQL工具进行备份&#xff0c;但是如果在项目运行当中&#xff0c;我们需要对数据进行实时&#xff0c;或者是每隔一星期&#xff0c;一个月&#xff0c;等等进行数据…

JSF简单Ajax示例

今天&#xff0c;我们将看到一些使用JSF的Ajax简单样本。 如果要查看有关JSF / Web应用程序的其他文章&#xff0c;请单击以下链接&#xff1a; 重定向后的JSF持久化对象和消息 &#xff0c; 使用JAAS和JSF进行用户登录验证 &#xff0c; JSF&#xff1a;Converter and Bean Au…

常用的好用的window工具

1. FastStone Capture截图录屏软件 百度软件中心&#xff1a;http://rj.baidu.com/soft/detail/13504.html?ald 注册企业版&#xff1a; 用户名&#xff1a;c1ikm 注册码&#xff1a;AXMQX-RMMMJ-DBHHF-WIHTV 中文输入乱码解决方法&#xff1a; 2. Notepad文本编辑器&#xff…

表分区

http://www.cnblogs.com/leestar54/p/6225821.html转载于:https://www.cnblogs.com/jouny/p/6262850.html

java飞鸽传书_feige 飞鸽传书源代码java 实现不错的联系网络编程的资料飞鸽传书的GUI(java实现) - 下载 - 搜珍网...

我的飞鸽传书/FileFilter.java我的飞鸽传书/FileNameExtensionFilter.java我的飞鸽传书/飞鸽传书/classes/feige/About.class我的飞鸽传书/飞鸽传书/classes/feige/ConnectOthers$ReadMessageThread.class我的飞鸽传书/飞鸽传书/classes/feige/ConnectOthers.class我的飞鸽传书…