如何解决“无法延迟初始化角色集合”的Hibernate异常

本文翻译自:How to solve the “failed to lazily initialize a collection of role” Hibernate exception

I have this problem: 我有这个问题:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed org.hibernate.LazyInitializationException:无法延迟初始化角色集合:mvc3.model.Topic.comments,没有会话或会话被关闭

Here is the model: 这是模型:

@Entity
@Table(name = "T_TOPIC")
public class Topic {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @ManyToOne
    @JoinColumn(name="USER_ID")
    private User author;

    @Enumerated(EnumType.STRING)    
    private Tag topicTag;

    private String name;
    private String text;

    @OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
    private Collection<Comment> comments = new LinkedHashSet<Comment>();

    ...

    public Collection<Comment> getComments() {
           return comments;
    }

}

The controller, which calls model looks like the following: 调用模型的控制器如下所示:

@Controller
@RequestMapping(value = "/topic")
public class TopicController {

    @Autowired
    private TopicService service;

    private static final Logger logger = LoggerFactory.getLogger(TopicController.class);


    @RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
    public ModelAndView details(@PathVariable(value="topicId") int id)
    {

            Topic topicById = service.findTopicByID(id);
            Collection<Comment> commentList = topicById.getComments();

            Hashtable modelData = new Hashtable();
            modelData.put("topic", topicById);
            modelData.put("commentList", commentList);

            return new ModelAndView("/topic/details", modelData);

     }

}

The jsp-page looks li the following: jsp页看起来如下所示:

<%@page import="com.epam.mvc3.helpers.Utils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
      <title>View Topic</title>
</head>
<body>

<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>

</c:forEach>
</ul>
</body>
</html>

Exception is rised, when viewing jsp. 查看jsp时会引发异常。 In the line with c:forEach loop c:forEach循环一致


#1楼

参考:https://stackoom.com/question/nHnf/如何解决-无法延迟初始化角色集合-的Hibernate异常


#2楼

If you know that you'll want to see all Comment s every time you retrieve a Topic then change your field mapping for comments to: 如果您知道每次检索Topic都想查看所有Comment则将comments的字段映射更改为:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

Collections are lazy-loaded by default, take a look at this if you want to know more. 默认情况下,集合是延迟加载的,如果您想了解更多信息,请查看内容。


#3楼

your list is lazy loading, so the list wasn't loaded. 您的列表是延迟加载的,因此列表尚未加载。 call to get on the list is not enough. 仅凭电话进入名单是不够的。 use in Hibernate.initialize in order to init the list. 在Hibernate.initialize中使用以初始化列表。 If dosnt work run on the list element and call Hibernate.initialize for each . 如果dosnt工作在list元素上运行,并为每个调用Hibernate.initialize。 this need to be before you return from the transaction scope. 这需要在您从事务范围返回之前。 look at this post. 这个帖子。
search for - 搜索 -

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 

#4楼

In order to lazy load a collection there must be an active session. 为了延迟加载集合,必须有一个活动会话。 In a web app there are two ways to do this. 在Web应用程序中,有两种方法可以执行此操作。 You can use the Open Session In View pattern, where you use an interceptor to open the session at the beginning of the request and close it at the end. 您可以使用“ 在视图中打开会话”模式,在该模式中,您可以使用拦截器在请求开始时打开会话,并在请求结束时将其关闭。 The risk there is that you have to have solid exception handling or you could bind up all your sessions and your app could hang. 这样做的风险是您必须进行可靠的异常处理,否则您可能会束缚所有会话,并且应用程序可能会挂起。

The other way to handle this is to collect all the data you need in your controller, close your session, and then stuff the data into your model. 处理此问题的另一种方法是收集控制器中所需的所有数据,关闭会话,然后将数据填充到模型中。 I personally prefer this approach, as it seems a little closer to the spirit of the MVC pattern. 我个人更喜欢这种方法,因为它似乎更接近MVC模式的精神。 Also if you get an error from the database this way you can handle it a lot better than if it happens in your view renderer. 同样,如果您通过这种方式从数据库中获取错误,则与在视图渲染器中发生的错误相比,可以更好地处理该错误。 Your friend in this scenario is Hibernate.initialize (myTopic.getComments()). 在这种情况下,您的朋友是Hibernate.initialize (myTopic.getComments())。 You will also have to reattach the object to the session, since you're creating a new transaction with every request. 您还必须将对象重新连接到会话,因为您将为每个请求创建一个新事务。 Use session.lock(myTopic,LockMode.NONE) for that. 为此使用session.lock(myTopic,LockMode.NONE)。


#5楼

From my experience, I have the following methods to solved the famous LazyInitializationException: 根据我的经验,我有以下方法来解决著名的LazyInitializationException:

(1) Use Hibernate.initialize (1)使用Hibernate.initialize

Hibernate.initialize(topics.getComments());

(2) Use JOIN FETCH (2)使用JOIN FETCH

You can use the JOIN FETCH syntax in your JPQL to explicitly fetch the child collection out. 您可以在JPQL中使用JOIN FETCH语法来显式提取子集合。 This is some how like EAGER fetching. 这有点像EAGER提取。

(3) Use OpenSessionInViewFilter (3)使用OpenSessionInViewFilter

LazyInitializationException often occur in view layer. LazyInitializationException通常在视图层中发生。 If you use Spring framework, you can use OpenSessionInViewFilter. 如果使用Spring框架,则可以使用OpenSessionInViewFilter。 However, I do not suggest you to do so. 但是,我不建议您这样做。 It may leads to performance issue if not use correctly. 如果使用不正确,可能会导致性能问题。


#6楼

it was the problem i recently faced which i solved with using 这是我最近遇到的问题,我通过使用解决了

<f:attribute name="collectionType" value="java.util.ArrayList" />

more detailed decription here and this saved my day. 这里更详细的说明,这节省了我的时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以在 Spring 配置文件中使用 `default-lazy-init` 属性来设置全局的延迟初始化。例如: ``` <beans default-lazy-init="true"> <!-- 其他 bean 定义 --> </beans> ``` 这将会导致所有的 bean 都采用延迟初始化的方式,除非在单独的 bean 定义中显式地设置 `lazy-init` 属性为 `false`。 另外,也可以通过在类路径中添加 `META-INF/spring.factories` 文件,并在该文件中添加如下内容来设置全局的延迟初始化: ``` org.springframework.context.annotation.ConfigurationClassPostProcessor.registerLazyInitialization=true ``` 最后,还可以使用 Spring 的 `AbstractApplicationContext` 类的 `setDefaultLazyInitialization` 方法来设置全局的延迟初始化,例如: ``` AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.setDefaultLazyInitialization(true); context.register(AppConfig.class); context.refresh(); ``` ### 回答2: 在Spring中,可以通过配置来设置全局的延迟初始化。要实现这个目标,可以按照以下步骤进行操作。 首先,在Spring的配置文件中,可以通过`<beans>`标签来设置全局的延迟初始化策略。可以使用`default-lazy-init`属性来指定全局的延迟初始化行为。将其设置为`true`,表示所有的bean都将被延迟初始化;将其设置为`false`,表示所有的bean都将立即初始化。例如: ```xml <beans default-lazy-init="true"> <!-- bean definitions here --> </beans> ``` 其次,如果需要对特定的bean进行自定义的延迟初始化设置,可以在相应的bean定义中使用`lazy-init`属性进行配置。将其设置为`true`,表示该bean将被延迟初始化;将其设置为`false`,表示该bean将立即初始化。例如: ```xml <bean id="myBean" class="com.example.MyBean" lazy-init="true"> <!-- bean properties and configuration here --> </bean> ``` 通过上述两种方式,可以实现全局的延迟初始化设置。这样可以有效地控制bean的初始化时机,避免在应用启动过程中加载过多的bean,从而提高应用的性能和响应速度。 ### 回答3: 在Spring中,我们可以使用lazy-init属性来设置全局的延迟初始化延迟初始化意味着在第一次访问bean时才会创建实例。相反,如果不设置延迟初始化Spring容器在启动时就会创建所有的bean实例。 要设置全局的延迟初始化,我们可以在Spring配置文件(通常是applicationContext.xml)中使用default-lazy-init属性。例如: <beans default-lazy-init="true"> <!-- bean definitions --> </beans> 在上面的示例中,默认的延迟初始化值设置为true,这意味着所有的bean都会被延迟初始化。如果想要某个特定的bean在启动时立即初始化,可以在其bean定义中明确设置lazy-init属性为false。 延迟初始化对于应用中一些不常用或资源消耗较大的bean很有用,可以提高应用的启动性能。但需要注意的是,如果一个bean在容器启动后需要立即使用,而它被延迟初始化了,那么可能会导致一些问题。因此,在选择是否延迟初始化时,需要仔细考虑应用的需求和性能权衡。 总结来说,要设置全局的延迟初始化,在Spring配置文件中使用default-lazy-init属性,并将其设为true。如果需要某个特定的bean立即初始化,可以在其bean定义中将lazy-init属性设为false。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值