代码之家  ›  专栏  ›  技术社区  ›  Jan Bodnar

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

  •  3
  • Jan Bodnar  · 技术社区  · 6 年前

    我有具有单向关系的用户和发布实体。我得到了 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: 当我试图从一个特定的用户获取所有文章时出现异常。

    根据这些,所以 answers ,处理此问题的最佳方法是使用 @Transactional 服务方法/类的注释。放置注释对我不起作用。我使用的是Wildfly服务器、Hibernate、MySQL和JavaEE MVC Web框架。

    我如何让它工作,即从用户那里获取帖子?我通过热切的加载成功地做到了这一点,但出于性能原因,不建议这样做。

    @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>
    

    这是我的坚持单位。

    错误消息:

    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)
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Dragan Bozanovic    6 年前

    您将返回会话边界之外的未初始化的集合代理(在本例中由事务划分)。

    您可以通过调用 Hibernate.initialize(posts) 或者只是打电话 posts.size() 在返回之前(第一种方法更清楚地描述了IMO的意图)。

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

    其他备选方案包括开放式会议(Anti-?)模式和 hibernate.enable_lazy_load_no_trans 但它们的灵活性较差,而且有自己的利弊。

    推荐文章