CDIマネージドビーンとステートフルセッションBeanを使用したLazyInitializationException
-
25-10-2019 - |
質問
ステートフルなセッションBeanが注入されたCDIマネージドビーン(JSFで使用されている@Namedが注釈付き)を持っています。このセッションBeanはサービスのようなもので、エンティティマネージャー(@persistenceContext(type = persistenceContextType.extended)で注釈が付いています)を持ち、いくつかのエンティティを操作するためにCOMメソッドを公開します。これらのエンティティは、会話を作成しているマネージドビーン上にあります。次に、JSFはマネージドビーンの方法を呼び出し、管理された豆は「サービス」(ステートフルセッションBean)の方法を呼び出します。これが最高のデザインかどうかはわかりませんが、うまく機能していました。しかし、怠zyでフェッチする必要があるコレクションがいくつかあるエンティティがあります。そして、初めてページを開くとうまく機能しているように見えますが、ボタンをクリックしたり、アクションを実行したりすると、LazyInitializationExceptionがあります。誰かがヒントを持っていますか?何か問題があるかどうかはわかりません。私はセッションビーンをステートフルのように配置し、永続性のコンテキストが拡張されました。このセッションBeanは、エンティティを持つマネージドビーン内に注入されます。なぜこの例外を投げているのですか?エンティティマネージャーはどのように閉鎖できますか?
これは、トラブルに陥っているエンティティのコードです。
@Entity
public class ParametrosVingentes implements Serializable {
public static final String ID = "settings";
private static final long serialVersionUID = 1L;
@Id
private String id;
@OneToOne
private ValorHora valorHora;
@OneToMany
@JoinTable(
name="BuscaSistecVingentes",
joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
inverseJoinColumns = @JoinColumn( name="agendamento_fk")
)
private List<AgendamentoBuscaSistec> agendamentosBuscaSistec;
@OneToMany
@JoinTable(
name="ExportacaoZeusVingentes",
joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
inverseJoinColumns = @JoinColumn( name="agendamento_fk")
)
private List<AgendamentoExportacaoZeus> agendamentosExportacaoZeus;
@OneToMany
@JoinTable(
name="ImportacaoZeusVingentes",
joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
inverseJoinColumns = @JoinColumn( name="agendamento_fk")
)
private List<AgendamentoImportacaoZeus> agendamentosImportacaoZeus;
public ParametrosVingentes() {
this.id = ID;
}
// getters and setters...
これはステートフルなセッションの豆です:
@Stateful
@LocalBean
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ParametrosService implements Serializable {
@PersistenceContext(type= PersistenceContextType.EXTENDED)
private EntityManager entityManager;
public void cadastrar(ValorHora valorHora){
ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
valorHoraDao.salvar(valorHora);
}
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<ValorHora> listarValorHora(){
ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
return valorHoraDao.getAll();
}
public boolean excluir(ValorHora valorHora){
if(valorHora.getRemessas() != null && !valorHora.getRemessas().isEmpty()){
return false;
}
ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
valorHoraDao.remover(valorHora);
return true;
}
public void cadastrar(AgendamentoBuscaSistec agendamentoBuscaSistec){
AgendamentoBuscaSistecDao agendamentoBuscaSistecDao = new AgendamentoBuscaSistecDao(entityManager);
agendamentoBuscaSistecDao.salvar(agendamentoBuscaSistec);
}
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<AgendamentoBuscaSistec> listarAgendamentoBuscaSistec(){
AgendamentoBuscaSistecDao agendamentoBuscaSistecDao = new AgendamentoBuscaSistecDao(entityManager);
return agendamentoBuscaSistecDao.getAgendamentos();
}
public void excluir(AgendamentoBuscaSistec agendamentoBuscaSistec){
AgendamentoBuscaSistecDao agendamentoBuscaSistecDao = new AgendamentoBuscaSistecDao(entityManager);
agendamentoBuscaSistecDao.remover(agendamentoBuscaSistec);
}
public void cadastrar(AgendamentoExportacaoZeus agendamentoExportacaoZeus){
AgendamentoExportacaoZeusDao agendamentoExportacaoZeusDao = new AgendamentoExportacaoZeusDao(entityManager);
agendamentoExportacaoZeusDao.salvar(agendamentoExportacaoZeus);
}
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<AgendamentoExportacaoZeus> listarAgendamentoExportacaoZeus(){
AgendamentoExportacaoZeusDao agendamentoExportacaoZeusDao = new AgendamentoExportacaoZeusDao(entityManager);
return agendamentoExportacaoZeusDao.getAgendamentos();
}
public void excluir(AgendamentoExportacaoZeus agendamentoExportacaoZeus){
AgendamentoExportacaoZeusDao agendamentoExportacaoZeusDao = new AgendamentoExportacaoZeusDao(entityManager);
agendamentoExportacaoZeusDao.remover(agendamentoExportacaoZeus);
}
public void cadastrar(AgendamentoImportacaoZeus agendamentoImportacaoZeus){
AgendamentoImportacaoZeusDao agendamentoImportacaoZeusDao = new AgendamentoImportacaoZeusDao(entityManager);
agendamentoImportacaoZeusDao.salvar(agendamentoImportacaoZeus);
}
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<AgendamentoImportacaoZeus> listarAgendamentoImportacaoZeus(){
AgendamentoImportacaoZeusDao agendamentoImportacaoZeusDao = new AgendamentoImportacaoZeusDao(entityManager);
return agendamentoImportacaoZeusDao.getAgendamentos();
}
public void excluir(AgendamentoImportacaoZeus agendamentoImportacaoZeus){
AgendamentoImportacaoZeusDao agendamentoImportacaoZeusDao = new AgendamentoImportacaoZeusDao(entityManager);
agendamentoImportacaoZeusDao.remover(agendamentoImportacaoZeus);
}
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public ParametrosVingentes getParametrosVingentes(){
return ParametrosUtil.getParametrosVingentes(entityManager);
}
public void atualizarParametrosVingentes(ParametrosVingentes parametrosVingentes){
ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
parametrosVingentes = parametrosVingentesDao.atualizar(parametrosVingentes);
}
}
マネージドビーンは、セッションBeanのメソッドgetParametrosvingentes()を呼び出します。 parametroSutilの静的な方法を使用して(存在する場合)または作成(存在しない場合)パラメトロシンガンセントを作成します。アプリケーションにパラメーターヴィットが1つしかない必要があるからです。他のコンポーネントで使用されるパラメーターを備えたのは豆です。これはparametroSutilのコードです:
public class ParametrosUtil {
public static synchronized ParametrosVingentes getParametrosVingentes(EntityManager entityManager){
ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
ParametrosVingentes parametrosVingentes = parametrosVingentesDao.buscar(ParametrosVingentes.ID);
if(parametrosVingentes == null){
parametrosVingentes = new ParametrosVingentes();
}
return parametrosVingentes;
}
public static synchronized ParametrosVingentes atualizarParametrosVingentes(ParametrosVingentes parametrosVingentes, EntityManager entityManager){
ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
return parametrosVingentesDao.atualizar(parametrosVingentes);
}
}
これはマネージドビーンです:
@Named(value = "parametros")
@ConversationScoped
public class Parametros implements Serializable {
public static final int VISAO_PARAMETROS_VINGENTES = 1;
public static final int VISAO_VALOR_HORA = 2;
public static final int VISAO_AGENDAMENTO_SISTEC = 3;
public static final int VISAO_AGENDAMENTO_EXPORTACAO_ZEUS = 4;
public static final int VISAO_AGENDAMENTO_IMPORTACAO_ZEUS = 5;
private int visaoAtual;
@EJB
private ParametrosService parametrosService;
@Inject
private Conversation conversation;
private ValorHora valorHora;
private AgendamentoBuscaSistec agendamentoBuscaSistec;
private AgendamentoExportacaoZeus agendamentoExportacaoZeus;
private AgendamentoImportacaoZeus agendamentoImportacaoZeus;
private List<ValorHora> listaValorHora;
private boolean listaValorHoraModificada;
private List<AgendamentoBuscaSistec> listaAgendamentoBuscaSistec;
private boolean listaAgendamentoBuscaSistecModificada;
private List<AgendamentoExportacaoZeus> listaAgendamentoExportacaoZeus;
private boolean listaAgendamentoExportacaoZeusModificada;
private List<AgendamentoImportacaoZeus> listaAgendamentoImportacaoZeus;
private boolean listaAgendamentoImportacaoZeusModificada;
private ParametrosVingentes parametrosVingentes;
public Parametros() {
this.visaoAtual = VISAO_PARAMETROS_VINGENTES;
}
@PostConstruct
public void init(){
this.conversation.begin();
this.parametrosVingentes = this.parametrosService.getParametrosVingentes();
}
public ParametrosVingentes getParametrosVingentes() {
return parametrosVingentes;
}
public List<ValorHora> getListaValorHora(){
if(this.listaValorHora == null || this.listaValorHoraModificada){
this.listaValorHoraModificada = false;
this.listaValorHora = this.parametrosService.listarValorHora();
}
return this.listaValorHora;
}
public List<AgendamentoBuscaSistec> getListaAgendamentoBuscaSistec(){
if(this.listaAgendamentoBuscaSistec == null || this.listaAgendamentoBuscaSistecModificada){
this.listaAgendamentoBuscaSistecModificada = false;
this.listaAgendamentoBuscaSistec = this.parametrosService.listarAgendamentoBuscaSistec();
}
return this.listaAgendamentoBuscaSistec;
}
public List<AgendamentoExportacaoZeus> getListaAgendamentoExportacaoZeus(){
if(this.listaAgendamentoExportacaoZeus == null || this.listaAgendamentoExportacaoZeusModificada){
this.listaAgendamentoExportacaoZeusModificada = false;
this.listaAgendamentoExportacaoZeus = this.parametrosService.listarAgendamentoExportacaoZeus();
}
return this.listaAgendamentoExportacaoZeus;
}
public List<AgendamentoImportacaoZeus> getListaAgendamentoImportacaoZeus(){
if(listaAgendamentoImportacaoZeus == null || this.listaAgendamentoImportacaoZeusModificada){
this.listaAgendamentoImportacaoZeusModificada = false;
this.listaAgendamentoImportacaoZeus = this.parametrosService.listarAgendamentoImportacaoZeus();
}
return this.listaAgendamentoImportacaoZeus;
}
public void atualizarParametrosVingentes(){
this.parametrosService.atualizarParametrosVingentes(this.parametrosVingentes);
}
// Other methods
これがJSFです:
<p:fieldset>
<h:panelGrid columns="2">
<h:outputLabel value="Valor da hora:" for="valorHoraVingente" />
<p:selectOneMenu id="valorHoraVingente" value="#{parametros.parametrosVingentes.valorHora}">
<f:selectItem itemLabel="Selecione" itemValue="#{null}" />
<f:selectItems value="#{parametros.listaValorHora}" />
</p:selectOneMenu>
<h:outputLabel value="Agendamento da Busca do Sistec:" for="agendamentoBuscaSistecVingente" />
<p:selectManyCheckbox id="agendamentoBuscaSistecVingente" value="#{parametros.parametrosVingentes.agendamentosBuscaSistec}">
<f:selectItem itemLabel="Selecione" itemValue="#{null}" />
<f:selectItems value="#{parametros.listaAgendamentoBuscaSistec}" />
</p:selectManyCheckbox>
<h:outputLabel value="Agendamento da Exportação para o Zeus:" for="agendamentoExportacaoZeusVingente" />
<p:selectManyCheckbox id="agendamentoExportacaoZeusVingente" value="#{parametros.parametrosVingentes.agendamentosExportacaoZeus}">
<f:selectItem itemLabel="Selecione" itemValue="#{null}" />
<f:selectItems value="#{parametros.listaAgendamentoExportacaoZeus}" />
</p:selectManyCheckbox>
<h:outputLabel value="Agendamento da Importação para o Zeus:" for="agendamentoImportacaoZeusVingente" />
<p:selectManyCheckbox id="agendamentoImportacaoZeusVingente" value="#{parametros.parametrosVingentes.agendamentosImportacaoZeus}">
<f:selectItem itemLabel="Selecione" itemValue="#{null}" />
<f:selectItems value="#{parametros.listaAgendamentoImportacaoZeus}" />
</p:selectManyCheckbox>
</h:panelGrid>
<p:commandButton value="Atualizar" action="#{parametros.atualizarParametrosVingentes}" update="@form" />
</p:fieldset>
ご覧のとおり、怠zyでフェッチする必要があるコレクションにバインドされたフィールドがあります。
そして、これはスタックトレースです:
WARNING: failed to lazily initialize a collection, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
at org.hibernate.collection.PersistentBag.isEmpty(PersistentBag.java:255)
at javax.faces.component.UIInput.isEmpty(UIInput.java:1257)
at javax.faces.component.UIInput.validateValue(UIInput.java:1144)
at javax.faces.component.UISelectMany.validateValue(UISelectMany.java:581)
at javax.faces.component.UIInput.validate(UIInput.java:967)
at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
at javax.faces.component.UIInput.processValidators(UIInput.java:698)
at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
at org.primefaces.component.fieldset.Fieldset.processValidators(Fieldset.java:197)
at javax.faces.component.UIForm.processValidators(UIForm.java:253)
at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
メソッドの最後に、サービスのgetParametrosvingentesでは、EntityManagerが明確であり、すべてのエンティティが分離されていると思います。それは問題でしょうか?
Mojarra 2.1.2とEJB 3.1を使用して、Glassfish 3でこれを実行しています。助けてくれてありがとう。
解決
さて、私はついに問題を解決しました! LazyInitializationExceptionがSelectManyCheckboxの検証フェーズにあるのを見ました。それから私はこれを検索し始め、このリンクを見つけました: http://old.nabble.com/-jira--created-(myfaces-3306)-%3ch%3aselectmanycheckbox%3e-%2b-jpa-with-hibernate-creates-hibernate-persistentcolection-どこでもnot.-not.-causes-td32463262.html
問題は、JSFがHibernateによって作成されたPersistentBagを使用しようとしていたことですが、使用しないことです。このソリューションは、jsfにwestistentBagの代わりにアレイリストを使用するように伝えるatributteを配置しました。
これをselectmanycheckbox内に追加することで実行できます。
<f:attribute name="collectionType" value="java.util.ArrayList" />