当前位置: 首页 > 知识库问答 >
问题:

Spring MVC Hibernate:无法初始化代理-没有会话

姜玉泽
2023-03-14

注意:关于我如何解决这个问题的例子,请看我自己对这个问题的回答。

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

org . hibernate . lazyinitializationexception:无法延迟初始化角色集合:com . my site . company . acknowledges,无法初始化代理-无会话

看了很多关于这个问题的其他问题,我明白为什么会出现这个异常,但是我不确定如何用好的方法修复它。我正在做以下事情:

  1. 我的 Spring MVC 控制器调用服务中的方法
  2. 服务方法调用 DAO 类中的方法
  3. DAO 类中的方法通过 Hibernate 获取实体对象,并将其返回到调用服务
  4. 服务将提取的对象返回到控制器
  5. 控制器将对象传递给视图 (JSP)
  6. 视图尝试迭代延迟加载的多对多关联(因此是代理对象)
  7. 引发异常的原因是会话此时已关闭,并且代理无法加载关联的数据

我以前使用过PHP和理论2,这种做事方式没有引起任何问题。我正在努力找出解决这个问题的最佳方法,因为到目前为止我找到的解决方案似乎并不太好:

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

我尝试在我的服务中使用< code>@Transactional,但是没有成功。这是有意义的,因为在我的服务方法返回后,我试图访问尚未加载的数据。理想情况下,我希望能够从我的视图中访问任何关联。我想在我的服务中初始化关联的缺点是我必须显式地定义我需要哪些数据——但是这取决于使用服务的上下文(控制器)。我不确定是否可以在我的控制器中这样做,而不会失去DBAL层提供的抽象。我希望这有意义。无论哪种方式,如果我不必总是明确地定义我希望哪些数据对我的视图可用,而是让视图做它自己的事情,那就太好了。如果这是不可能的,那么我只是在寻找最优雅的解决问题的方法。

下面是我的代码。

视图

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

<h1><c:out value="${company.name}" /> (ID: <c:out value="${company.id}" />)</h1>

<c:forEach var="acknowledgement" items="${company.acknowledgements}">
    <p><c:out value="${acknowledgement.name}" /></p>
</c:forEach>

控制器

@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);
    }
}

@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<Acknowledgement> acknowledgements;

    public Set<Acknowledgement> getAcknowledgements() {
        return acknowledgements;
    }

    public void setAcknowledgements(Set<Acknowledgement> acknowledgements) {
        this.acknowledgements = acknowledgements;
    }

    // Other getters and setters here
}

确认实体

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

    // Other fields + getters and setters here

}

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

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.mysite.company.entity</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven />

提前感谢!

共有3个答案

卫烨烁
2023-03-14

我投票支持服务层中的<code>Hibernate.initialize(myObject.getAssociation())(这也意味着<code>@Transactional</code>应该从DAO移动到服务方法)

恕我直言,服务方法应返回调用方所需的所有数据。如果调用方希望在视图上显示某些关联,则服务负责提供该数据。这意味着您可能有几个方法显然执行相同的操作(返回公司实例),但根据调用方的不同,可以获取不同的关联。

在一个项目中,我们有一个配置类,其中包含了关于应该获取哪些关联的信息,我们还有一个服务方法,它也接受该类作为参数。这种方法意味着我们只有一个足够灵活的方法来支持所有调用者。

@Override
public Company get(int id, FetchConfig fc) {
    Company result = this.companyDao.get(id);
    if (fc.isFetchAssociation1()) {
        Hibernate.initialize(result.getAssociation1());
    }
    ...
    return result;
}
诸超
2023-03-14

最简单和最透明的解决方案是OSIV模式。我相信你知道,在这个网站和其他地方有很多关于这种(反)模式和替代方案的讨论,所以没有必要再重复一遍。例如:

为什么Hibernate Open Session in View被认为是一种不好的做法?

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

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

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

薛保臣
2023-03-14

正如@PreDraw Maric所说,为实体assotiations使用不同初始化的写入服务html" target="_blank">方法可能是一种选择。

OpenSessionInView是一个不可讨论的模式,不过,它可能是您的解决方案。

另一种选择是设置

<代码>

财产。它旨在解决< code > org . hibernate . lazyinitializationexception 问题,从hibernate 4.1.6开始可用。

那幺,这个属性做什么?如果在当前未初始化代理中设置的会话关闭,它只会向Hibernate发出信号,通知它应该打开一个新会话。您应该知道,如果您有任何其他打开的会话也用于管理当前事务,则此新打开的会话将不同,除非是JTA,否则它可能不会参与当前事务。由于这种TX副作用,您应该小心防止系统中可能出现的副作用。

请在此处查找更多信息:http://blog.harezmi.com.tr/hibernates-new-feature-for-overcoming-frustrating-lazyinitializationexceptions并使用Hibernate.enable_Lazy_load_no_trans解决Hibernate Lazy Init问题

 类似资料:
  • 问题内容: 我有一个看起来像这样的错误: 无法初始化代理-没有会话 我正在使用java,hibernate和spring。尝试生成PDF文档时会出现此错误,我正在按照以下步骤即时生成它并存储在数据库中。 我通过POST方法向应用发送了请求。这将即时生成PDF并显示给用户。 在该请求之后,我发送了另一个请求,但是通过ajax发送了一个请求。这将生成相同的PDF,但会将其保存在数据库中。 该错误表明由

  • 问题内容: 我有2台物理服务器,我的Web应用程序命中该服务器由负载均衡器管理。我总是得到- org.hibernate.LazyInitializationException:无法初始化代理-没有会话 当其中一台服务器受到攻击而另一台服务器运行平稳而没有任何问题时。我有一个由应用程序启用和管理的本地托管缓存存储。仅当尝试从一个表访问一个特定的列时,才会发生此异常。不管选择哪个服务器,其余的操作都

  • 问题内容: 我的代码检索与用户有关的所有信息: 在简单地返回一组用户的ES。 我的问题是:即使会话已经关闭,为什么对象仍然具有其值(例如名称)?是该类的实例变量。但是为什么我不能检索其值却可以检索该类的常规实例变量? 是一个。 问题答案: 有关使用惰性关联的hibernate文档清楚地将这种访问称为错误。只有在会话仍处于打开状态时,才能与延迟关联的对象进行交互。文档的该部分还提供了访问对象的延迟关

  • 问题内容: 对数据库有以下查询: 在获取employee.address.street,employee.address.houseNumber或employee.address.city时,它将失败,但以下情况除外: 员工映射: 地址映射: 对于其他类(办公室,公司等),这​​是绝对正常的。如果注释,则在jsp应用程序中加载地址字段的行将正常工作。怎么了?顺便说一下,尽管有异常,它仍显示有关js

  • 问题内容: 我试图从数据库中的对象进行简单加载,但出现错误“无法初始化代理-没有会话”,知道吗?谢谢 问题答案: 尝试添加到validate方法: 发生的事情是,因为没有注释,所以没有与该方法关联的会话,并且每个查询都将在其自己的会话中运行,该会话随后将立即关闭。 该方法始终返回一个代理,与之不同(请参阅此处,了解load与get之间的差异)。 因此,返回了代理,但是由于缺少代理,因此立即关闭了创

  • 我尝试通过WebService从我的数据库中获取数据列表。我用spring和冬眠我读过这样或这样的主题 所以我试着把一些事务放在类的顶部,在我的方法上,等等,但是不起作用,或者我没有用正确的参数把正确的东西放在正确的地方。 谢谢,如果语法不好,请原谅 编辑:我想问题是来自我的类Personne在懒惰模式下得到了与许多其他实体的链接,这是否意味着在web服务上说,当我返回对象时,我不关心这个链接?或

  • 我试图从DB中的一个对象做一个简单的加载,但是我得到的错误是“Could not initialize proxy-no session”,有什么想法吗?谢谢

  • 问题内容: 我有一个具有以下结构的方法: 我在这里遇到的异常是代码的第二部分。在此,该字段是对其他域类的引用。 我尝试在属性检查之前添加和添加到代码中,但是没有用。我在这里做错了什么? upd:我尝试在检查属性之前调用方法,但是在方法调用之后立即调用is 的值。 问题答案: 我不认为您在做任何“错误”的事情,只是对象从hibernate会话中脱离了。我会尝试的几件事: 像这样将对象附加到hiber