简体   繁体   English

Wildfly - 如何启用事务以启用延迟加载

[英]Wildfly - how to enable transactions to enable lazy loading

I have User and Post entities with a unidirectional relationship. 我有User和Post实体具有单向关系。 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. 我收到org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:当我尝试从特定用户获取所有帖子时异常。

According to these SO answers , the optimal way to handle this is to use @Transactional annotation for the service method/class. 根据这些SO 答案 ,处理此问题的最佳方法是对服务方法/类使用@Transactional注释。 Placing annotations does not work for me. 放置注释对我不起作用。 I am using Wildfly server, Hibernate, MySQL, and Java EE MVC web framework. 我正在使用Wildfly服务器,Hibernate,MySQL和Java EE MVC Web框架。

How do I make it work, ie 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;
    }
}

This is my Service method. 这是我的服务方法。

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

This is my controller. 这是我的控制器。

<?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. 这是我的持久单元。

Error message: 错误信息:

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). 您正在从会话边界返回未初始化的集合代理(在这种情况下由事务划分)。

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). 您可以通过调用Hibernate.initialize(posts)或在返回之前调用posts.size()来初始化代理(第一种方法更清楚地描述了intent imo)。

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. 我最常使用的另一种方法是利用DTO,这样我就不必处理分离的对象,而且还因为能够根据客户的确切需求定制表示对象(以及一般的Web服务响应)他们。 Also that way the domain model (Hibernate entities) is decoupled from the presentation logic, allowing the two to evolve independently. 同样,域模型(Hibernate实体)与表示逻辑分离,允许两者独立发展。

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. 其他替代方案包括Open Session in View(反?)模式和hibernate.enable_lazy_load_no_trans属性,但它们不太灵活,各有利弊。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM