Spring MVC Hibernate:无法初始化代理 – 没有Session

注意:请参阅我自己对此问题的回答,以获取我如何解决此问题的示例.

我在Spring MVC 4 Hibernate 4项目中遇到以下异常:

org.hibernate.LazyInitializationException: failed to lazily initialize
a collection of role: com.mysite.Company.acknowledgements,could not
initialize proxy – no Session

在阅读了很多关于这个问题的其他问题后,我理解为什么会发生这种异常,但我不确定如何以一种好的方式解决它.我正在做以下事情:

> My Spring MVC控制器调用服务中的方法
> service方法调用DAO类中的方法
> DAO类中的方法通过Hibernate获取实体对象并将其返回给调用服务
>该服务将获取的对象返回给控制器
>控制器将对象传递给视图(JSP)
>视图尝试迭代延迟加载的多对多关联(因此是代理对象)
>抛出异常,因为此时会话已关闭,并且代理无法加载关联的数据

我之前使用过PHP和doctrine2,这种做事方式没有问题.我试图找出解决这个问题的最佳方法,因为到目前为止我找到的解决方案看起来并不那么好:

>急切加载关联,可能会加载大量不必要的数据
>调用Hibernate.initialize(myObject.getAssociation()); – 这意味着我必须遍历关联来初始化它们(我猜),而且事实上我必须这样做,有点使得延迟加载不那么整洁
>使用Spring过滤器在视图中打开会话,但我怀疑这是一件好事吗?

我尝试在我的服务中使用@Transactional,但没有运气.这是有道理的,因为我试图访问我的服务方法返回后尚未加载的数据.理想情况下,我希望能够从我的视图中访问任何关联.我想在我的服务中初始化关联的缺点是我必须明确定义我需要的数据 – 但这取决于使用服务的上下文(控制器).我不确定我是否可以在我的控制器中执行此操作而不会丢失DBAL层提供的抽象.我希望这是有道理的.无论哪种方式,如果我不必总是明确定义我想要哪些数据可用于我的视图,那就太好了,但只是让视图做它的事情.如果那是不可能的,那么我只是在寻找最优雅的解决方案.

以下是我的代码.

视图

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

调节器

@Controller
public class ProfileController {
    @Autowired
    private CompanyService companyService;

    @RequestMapping("/profile/view/{id}")
    public String view(Model model,@PathVariable int id) {
        Company company = this.companyService.get(id);
        model.addAttribute("company",company);

        return "viewCompanyProfile";
    }
}

服务

@Service
public class CompanyServiceImpl implements CompanyService {
    @Autowired
    private CompanyDao companyDao;

    @Override
    public Company get(int id) {
        return this.companyDao.get(id);
    }
}

DAO

@Repository
@Transactional
public class CompanyDaoImpl implements CompanyDao {
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Company get(int id) {
        return (Company) this.sessionFactory.getCurrentSession().get(Company.class,id);
    }
}

公司实体

@Entity
@Table(name = "company")
public class Company {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    // Other fields here

    @ManyToMany
    @JoinTable(name = "company_acknowledgement",joinColumns = @JoinColumn(name = "company_id"),inverseJoinColumns = @JoinColumn(name = "acknowledgement_id"))
    private Set

确认实体

@Entity
public class Acknowledgement {
    @Id
    private int id;

    // Other fields + getters and setters here

}

mvc-dispatcher-servlet.xml(它的一部分)

提前致谢!

最佳答案
最简单,最透明的解决方案是OSIV模式.我相信你已经知道,关于这个(反)模式以及这个网站和其他地方的替代方案都有很多讨论,所以不需要再重复一遍.例如:

Why is Hibernate Open Session in View considered a bad practice?

但是,在我看来,并非所有对OSIV的批评都是完全准确的(例如,在您的视图呈现之前事务不会提交?真的吗?如果您使用的是Spring实现,那么https://stackoverflow.com/a/10664815/1356423)

另外,请注意JPA 2.1引入了Fetch Graphs的概念,它可以让您更好地控制加载的内容.我还没有尝试过,但也许这可能是最终解决这个长期存在的问题!

http://www.thoughts-on-java.org/2014/03/jpa-21-entity-graph-part-1-named-entity.html

相关文章

这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
今天小编给大家分享的是一文解析spring中事务的传播机制,相...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...