JPA Lazy Loading

我在JPA实体中有延迟加载属性的问题。 我读了许多类似的问题,但它们与spring或hibernate有关,它们的问题不适用或有用。

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

@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 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 oauthLogins = user2.getOauthLogins(); 

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

 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非常相似的模式,它运行顺利。 任何想法? 谢谢

PS。 这是一个JPA应用程序,我没有hibernate会话等。

你可以使用的选择很少:

使用级联持久性:

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

在你的Servlet中:

 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 oauthLogins = user.getOauthLogins(); 

这应该做,加上你有一个事务和更少的JDBC调用。

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

EJB中的预取集合

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

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

这对于您希望在保留FetchType.LAZY同时使用User获取OAuthLogin集合并且仅针对该特定集合避免LazyInitializationException每种情况都很有用。

在View Filter中使用Open Entity Manager

只是谷歌,你会发现很多例子

对于跨越每个实体应用程序的每个懒惰地获取的关联,这基本上会阻止LazyInitializationException

PS:

  1. 如果不使用Spring,为什么使用@Transactional (默认情况下甚至不适用于HttpServlet
  2. 它曾适用于WebLogic,可能使用某种定制的解决方案

LazyInitializationException表示您在关联的会话关闭后访问延迟集合。

由于你的代码看起来很好,你的问题可能与JPA和Hibernate中的这个问题LazyInitializationException相同

您可以validation您的交易是在方法开头打开的吗?

要在JPA中初始化laze,你需要调用一个jar库并启动它,如果是maven或者手动的例子,如果你需要laze,在maven中使用jar
jar de.empulse.eclipselink 更多信息 http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving#Use_the_Maven_plugin