Hibernate &引用;无法初始化代理-无会话“;有一个开放的会议
我使用JSF2(MyFaces2.1.7和PrimeFaces3.4.2)、CDI(Weld servlet 1.1.10)、JPA2(Hibernate 4.1.7)和Lombok 0.11.2。所有这些都在Tomcat6和7上运行 我使用通过Hibernate &引用;无法初始化代理-无会话“;有一个开放的会议,hibernate,jsf,jpa,cdi,myfaces,Hibernate,Jsf,Jpa,Cdi,Myfaces,我使用JSF2(MyFaces2.1.7和PrimeFaces3.4.2)、CDI(Weld servlet 1.1.10)、JPA2(Hibernate 4.1.7)和Lombok 0.11.2。所有这些都在Tomcat6和7上运行 我使用通过过滤器实现的模式 @Advanced @Data @Slf4j public class TransactionalFilter implements Filter, Serializable { private static final lo
过滤器实现的模式
@Advanced
@Data
@Slf4j
public class TransactionalFilter implements Filter, Serializable {
private static final long serialVersionUID = 999173590695648899L;
@Inject
private EntityManager em;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
boolean newTransaction = false;
EntityTransaction tx = em.getTransaction();
if (!tx.isActive()) {
tx.begin();
newTransaction = true;
}
try {
chain.doFilter(request, response);
if (newTransaction && tx.isActive()) {
tx.commit();
}
} catch (Exception e) {
if (newTransaction && tx.isActive()) {
tx.rollback();
}
throw new ServletException(e);
}
}
(...)
}
注入的RequestScoped
EntityManager
由myEntityManager工厂提供,该工厂也为我的所有服务提供了它
@ApplicationScoped
@Data
@Slf4j
public class TransactionalEntityManagerFactory implements Serializable {
private static final String PU_NAME = "fr.senat.dosleg";
private static final long serialVersionUID = -3595175390458199193L;
private EntityManagerFactory emf;
/** (...)
* @return un nouvel EntityManager.
*/
@Produces
@RequestScoped
public EntityManager getEntityManager() {
if (emf == null) {
emf = Persistence.createEntityManagerFactory(PU_NAME);
}
return emf.createEntityManager();
}
/**(...)
* @param em le gestionnaire d'entité à libérer.
*/
public void closeEntityManager(@Disposes EntityManager em) {
if (em != null && em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
if (em != null && em.isOpen()) {
em.close();
}
}
}
这一切都很好,直到我添加了下面Controle实体中显示的列表
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude = { "organisme", "groupePolitique", "lois", "livrables",
"acteurs", "themes" })
public class Controle implements Serializable {
private static final long serialVersionUID = -6471695606036735891L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@NotNull
@Size(max = 256, message = "trop long.")
private String libelle;
@Pattern(regexp = Constants.URL_PATTERN, message = "pas au bon format")
private String url;
@NotNull
@Type(type = "fr.senat.util.hibernate.usertype.OuiNonSmallType")
private boolean initiativeDesGroupes;
@NotNull
@Type(type = "fr.senat.util.hibernate.usertype.OuiNonSmallType")
private boolean courDesComptes;
@NotNull
private int anneeCreation;
@Embedded
private EcheanceControle echeance = new EcheanceControle();
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "ORGCOD")
private Organisme organisme;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "GRPPOL")
private GroupePolitique groupePolitique;
@ManyToMany
@JoinTable(name = "CONTROLE_LOI", joinColumns = @JoinColumn(name = "CON_ID"), inverseJoinColumns = @JoinColumn(name = "LOICOD"))
private List<Loi> lois;
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
@JoinColumn(name = "CON_ID", nullable = false)
private List<LivrableControle> livrables;
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
@JoinColumn(name = "CON_ID", nullable = false)
private List<ActeurControle> acteurs;
@ManyToMany
@JoinTable(name = "THEME_CONTROLE", joinColumns = @JoinColumn(name = "CON_ID"), inverseJoinColumns = @JoinColumn(name = "THECLE"))
private List<Theme> themes;
(...)
}
这就是错误所在
<?xml version="1.0" encoding="utf-8"?>
<partial-response>
<error>
<error-name>org.hibernate.LazyInitializationException</error-name>
<error-message><![CDATA[could not initialize proxy - no Session]]></error-message>
</error>
</partial-response>
如果有人想试一试,这里有一些来自该方法调试的提示
classmodeltype=expression.getType(facesContext.getELContext())代码>是java.util.List
Collection.class.isAssignableFrom(modelType)
为true
collectionTypeAttr!=null
为false
Collection.class.isAssignableFrom(modelType)
为true
Collection componentValue=(Collection)component.getValue()
是一个PersistenBag
,它似乎使用数据(storedSnapshot
和角色
)正确初始化,但具有空的会话
targetForConvertedValues=(componentValue!=null?componentValue.getClass():modelType).newInstance()
最终成为一个持久包
,所有内容都为空(包括数据)。这可能是问题所在吗
boolean isArray=(targetForConvertedValues.getClass().isArray())代码>为false
((集合)targetForConvertedValues)。添加(值)代码>是一切都出错的地方
有什么想法吗?当您从数据库接收到包含集合的对象时,默认情况下,Hibernate中的集合是延迟加载的,而不是列表或集合,该列表或集合有一个代理。调用该集合的getter方法后,将获取该集合。但是,如果对象所源自的会话已关闭或不再可访问(不应在OpenSessionInView筛选器的约束范围内),则会出现问题
如果对象由不同的会话处理,您可以尝试调用session.merge
。或者,您可以在获取期间手动调用列表的getter
,这将触发代理。或者,您可以在集合中添加FetchType.Eager
,在这种情况下,即使在提取时,对象也不会是代理,而是真实的对象
但我看到您正在使用Weld进行CDI,为什么不使用支持事务管理的Seam持久化模块呢?然后,您将能够非常快速地实现视图中的开放会话方法
在我看来,这是我在Mojarra发现的一个非常讨厌的bug,在这个版本的MyFaces中可能也是如此。最基本的是,当它进行验证时,它会复制列表,但它使用集合的具体类型,使用无参数构造函数来创建集合。在hibernate的例子中,这个新列表没有运行所有的init代码,也没有链接回会话。我花了很长时间调试Mojarra源代码,以了解到底发生了什么
我发现我必须使用collectionType属性并将其设置为java.util接口类型。在没有明确告诉JSF要使用的集合类型的情况下,我不再处理集合 默认情况下,您的集合是延迟加载的。如果您试图在会话上下文之外访问列表,但代理未加载,它将发出抱怨,因为代理对象无法再访问其会话。如果您认为对象来自另一个会话,请尝试session.merge将对象合并到当前会话。或者,如果您愿意,可以在您的集合中添加eager,尽管在大多数情况下并不需要它。如StackTrace所示,异常发生在验证期间,在实际进入我的Bean代码之前。因此,我不知道在哪里添加手动合并的“hack”。FetchType。如问题中所述,我已经尝试过了。这并不能改变问题。我可能会查看PersistenceModule,但我认为对于我需要的简单的东西来说,它可能有点“大”。谢谢您的回复。我不相信这是解决方案,因为提供的stacktrace表明异常发生在PersistentBag内部,我认为如果Hibernate没有意识到这是一个代理,则不会发生这种情况。但是,我尝试将@CollectionType(type=“java.util.List”)
添加到我的私有列表主题中代码>我得到了一个自定义类型没有实现UserCollectionType:java.util.List
:也许我还不明白你的建议是什么?我最初也这么认为。就像我说的,花了很长时间才发现(浪费了一整天)试一下,这是一个小小的改变。如果它不起作用,那么你知道什么是不起作用的。它在视图中,而不是实体中。它位于多个选定组件上。感谢您的跟进。我想尝试一下您的建议,但在
中、PrimeFaces参考资料中或互联网上找不到有关collectionType
属性的任何信息。可以更具体一点吗?它是基类上的标准jsf属性。下面是一些描述问题或属性的其他链接:最后,我实际上必须将collectionType
设置为实际实现ArrayList
,而不是接口。我还必须确保我的转换器在那里。现在它开始工作了。这难道不能被认为是myfaces或primefaces上的一个bug,或者这是正常的吗?
<?xml version="1.0" encoding="utf-8"?>
<partial-response>
<error>
<error-name>org.hibernate.LazyInitializationException</error-name>
<error-message><![CDATA[could not initialize proxy - no Session]]></error-message>
</error>
</partial-response>
PersistentBag(AbstractPersistentCollection).withTemporarySessionIfNeeded(LazyInitializationWork<T>) line: 180
PersistentBag(AbstractPersistentCollection).initialize(boolean) line: 520
PersistentBag(AbstractPersistentCollection).write() line: 345
PersistentBag.add(Object) line: 291
_SharedRendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, String[], boolean) line: 339
RendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, Object, boolean) line: 1088
RendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, Object) line: 1056
HtmlCheckboxRenderer(HtmlCheckboxRendererBase).getConvertedValue(FacesContext, UIComponent, Object) line: 525
SelectManyButtonRenderer.getConvertedValue(FacesContext, UIComponent, Object) line: 36
SelectManyButton(UISelectMany).getConvertedValue(FacesContext, Object) line: 402
SelectManyButton(UIInput).validate(FacesContext) line: 584
SelectManyButton(UISelectMany).validate(FacesContext) line: 393
SelectManyButton(UIInput).processValidators(FacesContext) line: 274
HtmlPanelGrid(UIComponentBase).processValidators(FacesContext) line: 1421
Panel(UIComponentBase).processValidators(FacesContext) line: 1421
Panel.processValidators(FacesContext) line: 297
HtmlForm(UIForm).processValidators(FacesContext) line: 209
HtmlBody(UIComponentBase).processValidators(FacesContext) line: 1421
UIViewRoot(UIComponentBase).processValidators(FacesContext) line: 1421
UIViewRoot._processValidatorsDefault(FacesContext) line: 1401
UIViewRoot.access$500(UIViewRoot, FacesContext) line: 74
UIViewRoot$ProcessValidatorPhaseProcessor.process(FacesContext, UIViewRoot) line: 1508
UIViewRoot._process(FacesContext, PhaseId, UIViewRoot$PhaseProcessor) line: 1357
UIViewRoot.processValidators(FacesContext) line: 799
ProcessValidationsExecutor.execute(FacesContext) line: 38
LifecycleImpl.executePhase(FacesContext, PhaseExecutor, PhaseListenerManager) line: 170
LifecycleImpl.execute(FacesContext) line: 117
CodiLifecycleWrapper.execute(FacesContext) line: 95
FacesServlet.service(ServletRequest, ServletResponse) line: 197
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 290
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
PrettyFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 145
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
ApplicationDispatcher.invoke(ServletRequest, ServletResponse, ApplicationDispatcher$State) line: 646
ApplicationDispatcher.processRequest(ServletRequest, ServletResponse, ApplicationDispatcher$State) line: 436
ApplicationDispatcher.doForward(ServletRequest, ServletResponse) line: 374
ApplicationDispatcher.forward(ServletRequest, ServletResponse) line: 302
PrettyFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 137
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
TransactionalFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 60
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
SetUtf8CharacterEncodingFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 44
(...)
Thread.run() line: 662
_SharedRendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, String[], boolean) (line 143)