Wildfly - как включить транзакции, чтобы включить отложенную загрузку - PullRequest
0 голосов
/ 21 мая 2018

У меня есть пользовательские и почтовые объекты с однонаправленными отношениями.Я получаю исключение org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:, когда пытаюсь получить все сообщения от определенного пользователя.

Согласно этим SO ответам , оптимальный способ справиться с этим - использовать @Transactional аннотацию для метода / класса обслуживания.Размещение аннотаций не работает для меня.Я использую сервер Wildfly, Hibernate, MySQL и веб-фреймворк Java EE MVC.

Как мне заставить его работать, т.е. получать сообщения от пользователя?Мне удалось сделать это через энергичную загрузку, но это не рекомендуется из соображений производительности.

@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 Ответ

0 голосов
/ 25 мая 2018

Вы возвращаете неинициализированный прокси-сервер коллекции вне границ сеанса (в данном случае он разграничивается транзакцией).

Вы можете инициализировать прокси, вызвав Hibernate.initialize(posts) или просто позвонив posts.size(), прежде чем вернуть его.(первый подход более четко описывает намерение imo).

Альтернативой, которую я использую чаще всего, является использование DTO, чтобы мне не приходилось иметь дело с отсоединенными объектами, но также из-за способностиадаптировать объекты презентации (и ответы веб-служб в целом) к точным потребностям клиентов, использующих их.Также таким образом модель предметной области (сущности Hibernate) отделена от логики представления, что позволяет двум развиваться независимо.

Другие альтернативы включают шаблон Open Session in View (anti-?) И свойство hibernate.enable_lazy_load_no_trans, ноони менее гибки и имеют свои плюсы и минусы.

...