【问题标题】:How to make OpenSessionInViewInterceptor work in Spring mvc如何使 OpenSessionInViewInterceptor 在 Spring mvc 中工作
【发布时间】:2019-05-22 03:30:24
【问题描述】:

我正在尝试在 spring mvc 中设置 OpenSessionInViewInterceptor 来修复:org.hibernate.LazyInitializationException: could not initialize proxy - no Session。

以下是我已有的代码以及错误的来源。

AppConfig.java

@Configuration
@PropertySource("classpath:db.properties")
@EnableTransactionManagement
@ComponentScans(value = { @ComponentScan("com.debugger.spring.web.tests"),  @ComponentScan("com.debugger.spring.web.service"), @ComponentScan("com.debugger.spring.web.dao"),
@ComponentScan("com.debugger.spring.web.controllers") })
public class AppConfig implements WebMvcConfigurer {

@Autowired
private Environment env;

@Bean
public LocalSessionFactoryBean getSessionFactory() {
    LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();

    Properties props = new Properties();

    // Setting JDBC properties
    ...

    // Setting Hibernate properties
    ...

    // Setting C3P0 properties
        ...

    return factoryBean;
}

@Bean
public OpenSessionInViewInterceptor openSessionInViewInterceptor() {
    OpenSessionInViewInterceptor openSessionInViewInterceptor = new OpenSessionInViewInterceptor();
    openSessionInViewInterceptor.setSessionFactory(getSessionFactory().getObject());
    return openSessionInViewInterceptor;
}
}

featured.jsp

<c:choose>
                            <c:when
                                test='${article.user.isSubscribed() and article.user.subscription.type eq "silver" }'>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span
                                    class="silvername"> <c:out value="${article.user.name}"></c:out></span></a>
                            </c:when>
                            <c:when
                                test='${article.user.isSubscribed() and article.user.subscription.type eq "gold" }'>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span
                                    class="goldname"> <c:out value="${article.user.name}"></c:out></span></a>
                            </c:when>
                            <c:when
                                test='${article.user.isSubscribed() and article.user.subscription.type eq "premium" }'>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span
                                    class="premiumname"> <c:out
                                            value="${article.user.name}"></c:out></span></a>
                            </c:when>
                            <c:otherwise>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span>
                                        <c:out value="${article.user.name}"></c:out>
                                </span></a>
                            </c:otherwise>
                        </c:choose>

${article.user.isSubscribed()} 最有可能因为无法获取用户而引发错误。我希望它在不使用 Eager fetch 的情况下运行,我认为我可以通过正确设置 OpenSessionInViewInterceptor 来实现它。

【问题讨论】:

    标签: java hibernate spring-mvc interceptor


    【解决方案1】:

    在您的配置类中覆盖 WebMvcConfigurer#addInterceptors(InterceptorRegistry)

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        OpenSessionInViewInterceptor openSessionInViewInterceptor = new OpenSessionInViewInterceptor();
        openSessionInViewInterceptor.setSessionFactory(getSessionFactory().getObject());
    
        registry.addWebRequestInterceptor(openSessionInViewInterceptor).addPathPatterns("/**");
    }
    

    还在配置类中添加@EnableWebMvc

    回应 OP 的评论:

    我不确定它为什么不起作用。在我看来一切都很好。还有另一种方法可以实现:

    设置hibernate.enable_lazy_load_no_trans属性true

    请参阅23.9.1. Fetching properties in Hibernate User Guide 了解更多信息。

    但这不是指南中所述的一个非常好的选择:

    虽然启用此配置可​​以使 LazyInitializationException走开,最好用一个fetch计划 保证所有属性在之前正确初始化 会话已关闭。

    In reality, you shouldn’t probably enable this setting anyway.
    

    【讨论】:

    • 感谢您的回复,我按照您的建议做了,我使用了 registry.addWebRequestInterceptor 而不是 registry.addInterceptor,因为它说它不适用。运行修改后的应用程序后,它仍然返回与以前相同的错误(org.hibernate.LazyInitializationException:无法初始化代理 - 无会话)。
    • @DisplayName 请查看更新后的答案。
    • 我将该属性添加到我的 db.properties 但它仍然返回相同的错误。
    • @DisplayName 我认为您需要将此添加到jpaPropertyMapentityManagerFactorypersistence.xml 中,请参阅此链接pavel.cool/jee-tips/LazyInitializationException-solution。再次使用 hibernate.enable_lazy_load_no_trans 是一种反模式。所以,我建议你在使用它之前三思而后行! :)
    • 您知道更好的解决方案或将这种反模式的负面影响降至最低的方法吗?
    猜你喜欢
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 2014-02-09
    • 1970-01-01
    • 2018-08-02
    • 2012-06-17
    • 2014-12-21
    相关资源
    最近更新 更多