JPA 延迟加载 [英] JPA Lazy Loading

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

问题描述

我在 JPA 实体中遇到延迟加载属性的问题.我读过很多类似的问题,但它们与 spring 或 hibernate 相关,他们的回答要么不适用,要么有帮助.

I have a problem with lazy loading property in JPA entity. I read many similar questions, but they are related to spring or hibernate and their answears are either not applicable or helpful.

应用程序是 JEE,在 Wildfly 应用程序服务器上运行 JPA2.1.有两个实体,DAO 会话 bean 和 servlet 将它们组合在一起:

The application is JEE with JPA2.1 running on Wildfly application server. There are two entities, DAO session bean and servlet that puts it together:

@Entity
@Table(name = "base_user")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    int id;

    @OneToMany(fetch=FetchType.LAZY, mappedBy="user")
    List<OAuthLogin> oauthLogins;

}


@Entity
@Table(name = "oauth_login")
public class OAuthLogin implements Serializable {
    @ManyToOne
    @JoinColumn(name="user_id", nullable=false)
    User user;
}


@Stateless(name = "UserDAOEJB")
public class UserDAO {
    @PersistenceContext(unitName="OAUTHDEMO")
    EntityManager em;

    public User findById(int id) {
        User entity;
    entity = em.find(User.class, id);
        return entity;
    }
}


public class SaveUserServlet extends HttpServlet {
    @EJB
    UserDAO userDAO;

    @Transactional
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = new User(name);
        user.setEmail(email);
        System.out.println("Persisting user " + user);
        userDAO.persist(user);

        OAuthLogin fbLogin1 = new OAuthLogin(user, OAuthProvider.FACEBOOK, "1501791394");
        loginDAO.persist(fbLogin1);

        User user2 = userDAO.findById(user.getId());
        List<OAuthLogin> oauthLogins = user2.getOauthLogins();

当我运行这段代码时,它失败了:

When I run this code, it fails with:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cz.literak.demo.oauth.model.entity.User.oauthLogins, could not initialize proxy - no Session
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:572)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:212)
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:551)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:140)
org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294)
cz.literak.demo.oauth.servlets.SaveUserServlet.doPost(SaveUserServlet.java:66)

我使用了与 WebLogic/JPA1 非常相似的模式,并且运行流畅.任何的想法?谢谢

I used very similar pattern with WebLogic/JPA1 and it ran smoothly. Any idea? Thanks

附注.这是一个 JPA 应用程序,我没有休眠会话等.

PS. this is a JPA application, I do not have hibernate session etc.

推荐答案

您可以使用的替代方案很少:

There are few alternatives you can use:

@OneToMany(fetch=FetchType.LAZY, mappedBy="user", cascade = {CascadeType.PERSIST})
List<OAuthLogin> oauthLogins;

在你的 Servlet 中:

In your Servlet do:

User user = new User(name);
user.setEmail(email);
OAuthLogin fbLogin = new OAuthLogin(user, OAuthProvider.FACEBOOK, "1501791394");      
user.getOauthLogins().add(fbLogin) // this is enough assuming uni-directional association
userDAO.persist(user);
List<OAuthLogin> oauthLogins = user.getOauthLogins();

这应该可以,而且您有一个事务和更少的 JDBC 调用.

This should do, plus you have a single transaction and less JDBC calls.

这对于调用特定 Servlet 方法的特定用例很有帮助.

This is helpful for that specific use case where it that specific Servlet method call.

public User findById(int id, boolean prefetch) {
    User entity = em.find(User.class, id);
    if (prefetch) {
        // Will trigger 1 or size JDBC calls depending on your fetching strategy
        entity.getOauthLogins().size() 
    }
    return entity;
}

或者,使用条件覆盖获取模式

这对于您想要使用 User 获取 OAuthLogin 集合同时保留 FetchType.LAZY 并避免 的每种情况都有帮助LazyInitializationException 仅适用于该特定集合.

This is helpful for every case you want to fetch OAuthLogin collection with the User while preserving a FetchType.LAZY and avoid LazyInitializationException for that specific collection only.

谷歌一下,你会发现很多例子

Just Google it, you'll find plenty of examples

这将基本上防止LazyInitializationException,每个关联延迟获取,每个实体应用程序跨范围

This will basically prevents LazyInitializationException, per every association fetched lazily, per each Entity application cross-wide

附注:

  1. 如果不使用Spring,为什么要使用@Transactional(默认情况下甚至不适用于HttpServlet)
  2. 它曾适用于 WebLogic,可能使用某种量身定制的解决方案
  1. If not using Spring why are you using @Transactional (by default even doesn't apply to HttpServlet)
  2. It had worked for WebLogic probably using some kind of tailored made solution

这篇关于JPA 延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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