我有一个在Glassfish 4上正常运行的网络应用程序,我正在将它迁移到Wildfly。我明白了:
15:19:28,802 ERROR [io.undertow.request] (default task-33) UT005023: Exception handling request to /dvd_store/movie.xhtml: javax.servlet.ServletException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: dvd_store.entities.Movie.categories, could not initialize proxy - no Session
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:56) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:177) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:727) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_25]
at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_25]
Caused by: javax.faces.el.EvaluationException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: dvd_store.entities.Movie.categories, could not initialize proxy - no Session
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) [jsf-impl-2.2.6-jbossorg-4.jar:]
at javax.faces.component.UIViewAction.broadcast(UIViewAction.java:562) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) [jsf-impl-2.2.6-jbossorg-4.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.2.6-jbossorg-4.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) [jsf-impl-2.2.6-jbossorg-4.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
... 26 more
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: dvd_store.entities.Movie.categories, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:278) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
at dvd_store.controllers.MovieDisplayController.init(MovieDisplayController.java:49) [classes:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_25]
at com.sun.el.parser.AstValue.invoke(AstValue.java:275) [javax.el-3.0.0.jar:]
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304) [javax.el-3.0.0.jar:]
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) [jsf-impl-2.2.6-jbossorg-4.jar:]
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87) [jboss-jsf-api_2.2_spec-2.2.6.jar:2.2.6]
... 34 more
在movie.getCategories().size();
下面的<{1}}行抛出异常
@ManagedBean
@ViewScoped
public class MovieDisplayController implements Serializable {
@EJB
private MovieService ms;
private Movie movie;
private int id;
@ManagedProperty(value = "#{cartController}")
private CartController cartController;
// @PostConstruct // init() called in a f:viewParam
public void init() {
if (getId() == 0) {
String message = "Bad request. Please use a link from within the "
+ "system.";
msgError(message);
return;
}
movie = ms.find(getId());
if (movie == null) {
String message = "Bad request. Unknown movie.";
msgError(message);
return;
}
// hack to load the categories TODO
// see: https://community.oracle.com/thread/173733
movie.getCategories().size(); // MovieDisplayController.java:49
movie.getMoviesHasCrews().size();
sessionPut("movie", movie);
}
//...
}
其中:
@Entity
@Table(name = "movies")
public class Movie implements Serializable {
// bi-directional many-to-many association to Category
@ManyToMany
@JoinTable(name = "movies_has_categories", joinColumns = { @JoinColumn(
name = "movies_idmovie") }, inverseJoinColumns = { @JoinColumn(
name = "categories_idcategory") })
@NotEmpty(message = "Please enter categories for the movie")
private List<Category> categories;
public List<Category> getCategories() {
return this.categories;
}
//...
}
我是新来的休眠而且更喜欢这个。我对解决这个问题的方法很感兴趣,也适用于vanilla JPA(eclipselink)。我不会在我的项目中导入任何hiberante类(除了hibernate-validator
@NotEmpty
1}})。这是我的pom:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>gr.uoa.gr.regas.jee.dvdstore</groupId>
<artifactId>dvd_store</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.0.Final</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
答案 0 :(得分:1)
让关系变得热切,将导致所有JPA提供商提前阅读。如果您不确定是否始终需要获取的关系,则可能会在关系上进行使用JOIN FETCH的查询,以便在应用程序知道需要使用该关系时使用该查询。通过这种方式,您可以获得延迟加载的性能优势,并且在需要时可以在关闭的上下文外工作时仍然可以使用该模型。
查询中的联接提取强制使用单个查询读取它,而只是让它急切允许提供程序选择,使用自定义注释指定应如何读取它以实现效率目的。有关EclipseLink&#39}的解决方案,请参阅http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_joinfetch.htm,而Hibernate有@Fetch注释。
对于使用join的JPQL查询的示例可能是:
Query query = em.createQuery("SELECT movie FROM Movie movie LEFT JOIN FETCH movie.Categories LEFT JOIN FETCH movie.moviesHasCrews WHERE movie.id = :id");
query.setParameter("id", id);
return query.getSingleResult();
虽然使用命名查询可能会更好。
答案 1 :(得分:1)
实际上,size()hack或prefetching应该进入你的ejb方法,为两个提供者工作。当事务边界以find方法结束时,它会关闭entityManager并且不再附加您的实体。
一个解决方案:
使用布尔预取标志在MovieService中使用find()方法。
public Movie find(long id, boolean prefetch) {
Movie m = // normal find.
if (prefetch) {
m.getCategories().size();
// other prefetching like that
}
return m;
}
其他解决方案:急切加载。
答案 2 :(得分:1)
当工作应用程序从Glassfish迁移到Wildfly时会发生此问题。不幸的是,与EclipseLink不同,Wildfly的默认Hibernate JPA实现不允许您在关闭上下文后获取延迟关系。
许多解决方案建议使用热切的提取进行重构,但这不是一个好的解决方案,因为急切的提取会增加响应时间,并且通过重构数据库访问将风险引入到工作的应用程序中。
而是将Hibernate替换为EclipseLink作为Wildfly中的JPA持久性提供程序。 This library实用程序类将EclipseLink集成到Wildfly和the instructions are here。
您需要做的是将 eclipselink-2.6.0.jar (或您正在使用的任何版本)复制到 [WILDFLY_HOME] / modules / system / layers / base / org / eclipse / persistence / main 然后在同一文件夹中编辑 module.xml 以包含JAR:
<resources>
<resource-root path="jipijapa-eclipselink-1.0.1.Final.jar"/>
<resource-root path="eclipselink-2.6.0.jar">
<filter>
<exclude path="javax/**" />
</filter>
</resource-root>
</resources>
不要忘记重启服务器。
答案 3 :(得分:0)
热切的注释奏效了(我放弃了size()
次来电):
+import javax.persistence.FetchType;
#...
@@ -74,14 +75,15 @@ public class Movie implements Serializable {
- @ManyToMany
+ @ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "movies_has_categories", joinColumns = { @JoinColumn(
name = "categories_idcategory") })
@NotEmpty(message = "Please enter categories for the movie")
private List<Category> categories;
#...
- @OneToMany(mappedBy = "movy", cascade = CascadeType.PERSIST)
+ @OneToMany(mappedBy = "movy", cascade = CascadeType.PERSIST,
+ fetch = FetchType.EAGER)
private List<MoviesHasCrew> moviesHasCrews;
我最终使用了这个
@Stateless
public class MovieService {
@PersistenceContext
private EntityManager em;
public Movie findWithCrewAndCategories(int id) {
Movie find = em.find(Movie.class, id);
if (find != null) {
find.getCategories().size();
final List<MoviesHasCrew> moviesHasCrews = find.getMoviesHasCrews();
if (moviesHasCrews != null) {
moviesHasCrews.size();
}
}
return find;
}
}
与movie = ms.findWithCrewAndCategories(getId());
一样。
createQuery方法并没有真正起作用(不得不首先调整语句,不确定我做对了)
public Movie findWithCrewAndCategoriesQuery(int id) {
// BEFORE adding FETCH (as in LEFT JOIN __FETCH__):
// javax.servlet.ServletException:
// org.hibernate.LazyInitializationException: failed to lazily
// initialize a collection of role: dvd_store.entities.Movie.categories,
// could not initialize proxy - no Session
// AFTER adding FETCH (as in LEFT JOIN __FETCH__):
// javax.servlet.ServletException: javax.ejb.EJBException:
// javax.persistence.PersistenceException:
// org.hibernate.loader.MultipleBagFetchException: cannot simultaneously
// fetch multiple bags
Query query = em.createQuery("SELECT movie FROM Movie movie"
+ " LEFT JOIN FETCH movie.categories"
+ " LEFT JOIN FETCH movie.moviesHasCrews"
+ " WHERE movie.idmovie = :id");
query.setParameter("id", id);
return (Movie) query.getSingleResult();
}