Wildfly - 如何启用事务以启用延迟加载 [英] Wildfly - how to enable transactions to enable lazy loading

查看:140
本文介绍了Wildfly - 如何启用事务以启用延迟加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有User和Post实体具有单向关系。我收到 org.hibernate.LazyInitializationException:当我尝试从特定用户获取所有帖子时,无法懒惰地初始化角色集合:异常。

I have User and Post entities with a unidirectional relationship. I am getting org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: exception when I try to get all posts from a specific user.

根据这些SO 答案,处理此问题的最佳方法是对服务方法/类使用 @Transactional 注释。放置注释对我不起作用。我正在使用Wildfly服务器,Hibernate,MySQL和Java EE MVC Web框架。

According to these SO answers, the optimal way to handle this is to use @Transactional annotation for the service method/class. Placing annotations does not work for me. I am using Wildfly server, Hibernate, MySQL, and Java EE MVC web framework.

如何让它发挥作用,即从用户那里获取帖子?我设法通过急切加载来实现,但出于性能原因不推荐这样做。

How do I make it work, i.e. get the posts from a user? I managed to do it via eager loading, but this is not recommended for performance reasons.

@Transactional
public class UserService {

    private List<User> users;
    private Set<Post> posts;


    @PersistenceContext(unitName = "my-pu")
    private EntityManager em;

    public List<User> getUsers() {

        String qlQuery = "SELECT u FROM User u";
        Query query = em.createQuery(qlQuery);
        users = query.getResultList();

        return users;
    }

    @Transactional
    public Set<Post> getUserPosts(Long userId) {

            String qlQuery = "SELECT u FROM User u WHERE u.id = :userId";
            Query query = em.createQuery(qlQuery);
            query.setParameter("userId", userId);
            User user = (User) query.getSingleResult();

            posts = user.getPosts();

        return posts;
    }
}

这是我的服务方法。

@Path("users")
@Controller
public class UserController {

    @Inject
    private Models models;

    @Inject
    private UserService service;

    @GET
    @Produces("text/html")
    @View("showUsers.ftl")
    public void users() {

        List<User> users = service.getUsers();

        models.put("users", users);
    }

    @GET
    @Path("{id}")
    @Produces("text/html")
    @View("showUserPosts.ftl")    
    public void getPosts(@PathParam("id") Long userId) {

        System.out.println("here am i");

        Set<Post> posts = service.getUserPosts(userId);

        models.put("posts", posts);
    }
}

这是我的控制器。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
            <persistence-unit name="my-pu" transaction-type="JPA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/testdb?useSSL=false"/>
            <property name="javax.persistence.jdbc.user" value="testuser"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.password" value="test623"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.dialect.storage_engine" value="innodb"/>

            <property name="javax.persistence.schema-generation.database.action"
                      value="drop-and-create"/>      
            <property name="javax.persistence.sql-load-script-source"
                      value="META-INF/sql/data.sql" />        
        </properties>
    </persistence-unit>
</persistence>

这是我的持久性单位。

An this is my persistence unit.

错误讯息:

org.jboss.resteasy.spi.UnhandledException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.zetcode.model.User.posts, could not initialize proxy - no Session
    at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:257)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:195)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:539)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:461)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:231)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:137)
    at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:361)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:140)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:217)
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:67)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)


推荐答案

你从会话边界返回未初始化的集合代理(在这种情况下由事务划分)。

You are returning an uninitialized collection proxy out of session boundaries (demarcated by the transaction in this case).

您可以通过调用 Hibernate来初始化代理。初始化(发布)或者只是在返回之前调用 posts.size()(第一种方法更清楚地描述了意图imo)。

You can initialize the proxy by calling Hibernate.initialize(posts) or by just calling posts.size() before returning it (the first approach more clearly describes the intent imo).

我最常使用的另一种方法是使用DTO,这样我就不必处理分离的对象,而且还因为能够定制表示对象(和一般的Web服务响应)以满足使用它们的客户的确切需求。同样,域模型(Hibernate实体)与表示逻辑分离,允许两者独立发展。

An alternative that I use most often is to utilize DTOs, so that I don't have to deal with detached objects, but also because of the ability to tailor presentation objects (and web service responses in general) to the exact needs of clients using them. Also that way the domain model (Hibernate entities) is decoupled from the presentation logic, allowing the two to evolve independently.

其他替代方案包括Open View in View(反?) )模式和 hibernate.enable_lazy_load_no_trans 属性,但它们不够灵活,各有利弊。

Other alternatives include Open Session in View (anti-?) pattern and hibernate.enable_lazy_load_no_trans property, but they are less flexible and have their own pros and cons.

这篇关于Wildfly - 如何启用事务以启用延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆