Java JPA 延迟加载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21647947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA Lazy Loading
提问by Leos Literak
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.
我在 JPA 实体中遇到延迟加载属性的问题。我阅读了许多类似的问题,但它们与 spring 或 hibernate 相关,他们的回答要么不适用,要么有帮助。
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:
该应用程序是 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<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)
I used very similar pattern with WebLogic/JPA1 and it ran smoothly. Any idea? Thanks
我使用了与 WebLogic/JPA1 非常相似的模式,它运行流畅。任何的想法?谢谢
PS. this is a JPA application, I do not have hibernate session etc.
附注。这是一个 JPA 应用程序,我没有休眠会话等。
采纳答案by Ori Dar
There are few alternatives you can use:
您可以使用以下几种替代方法:
Use cascading persistence:
使用级联持久化:
@OneToMany(fetch=FetchType.LAZY, mappedBy="user", cascade = {CascadeType.PERSIST})
List<OAuthLogin> oauthLogins;
In your Servlet do:
在您的 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<OAuthLogin> oauthLogins = user.getOauthLogins();
This should do, plus you have a single transaction and less JDBC calls.
这应该可以,而且您只有一个事务和更少的 JDBC 调用。
This is helpful for that specific use case where it that specific Servlet method call.
这对于调用特定 Servlet 方法的特定用例很有帮助。
pre-fetch collection in EJB
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;
}
Alternatively, Override fetch mode using a criteria
或者,使用条件覆盖获取模式
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.
这对于您想要获取OAuthLogin
集合的每种情况都有帮助,User
同时保留 aFetchType.LAZY
并避免LazyInitializationException
仅用于该特定集合。
Use Open Entity Manager in View Filter
在视图过滤器中使用 Open Entity Manager
Just Google it, you'll find plenty of examples
谷歌一下,你会发现很多例子
This will basically prevents LazyInitializationException
, per every association fetched lazily, per each Entity application cross-wide
这将基本上防止LazyInitializationException
,每个延迟获取的关联,每个跨范围的实体应用程序
PS:
PS:
- If not using Spring why are you using
@Transactional
(by default even doesn't apply toHttpServlet
) - It had worked for WebLogic probably using some kind of tailored made solution
- 如果不使用 Spring 你为什么使用
@Transactional
(默认情况下甚至不适用于HttpServlet
) - 它可能使用某种量身定制的解决方案为 WebLogic 工作
回答by Andreas Aumayr
LazyInitializationException means that you access a lazy collection AFTER the associated session had been closed.
LazyInitializationException 意味着您在关联会话关闭后访问惰性集合。
As your code looks fine, your problem may be the same like in this question LazyInitializationException in JPA and Hibernate
由于您的代码看起来不错,您的问题可能与此问题中的LazyInitializationException in JPA 和 Hibernate 相同
Can you verify that your transaction is opened in the beginning of the method?
你能验证你的交易是在方法开始的时候打开的吗?
回答by GuapoSasa
To initialize laze in JPA, you need to invoke a jar library and start it, if it is with maven or manual
por example , if you need laze, use jar in maven
jar de.empulse.eclipselink
More infohttp://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving#Use_the_Maven_plugin
在JPA中初始化laze,需要调用一个jar库并启动它,如果是用maven或者manual por example,如果需要
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