I am using JPA 2.0
and Spring
in my development. My entity class contains two @ManyToMany
relationships.
@Entity("payment")
public class PaymentData implements Serializable
{
private Long pk;
private Collection<PaymentItemData> paymentItem;
/**
* minorPaymentItem
*
*/
private Collection<MinorPayItemData> minorPaymentItem;
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name = "payitem_m_assig",
joinColumns =
@JoinColumn(name = "pay_item_id", nullable = false),
inverseJoinColumns =
@JoinColumn(name = "minor_pay_item_id", nullable = false))
public Collection<MinorPayItemData> getMinorPaymentItem()
{
return minorPaymentItem;
}
/**
* @param minorPaymentItem the minorPaymentItem to set
*/
public void setMinorPaymentItem(final Collection<MinorPayItemData> value)
{
this.minorPaymentItem = value;
}
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name = "payitem_assigned",
joinColumns =
@JoinColumn(name = "pay_item_id", nullable = false),
inverseJoinColumns =
@JoinColumn(name = "pay_item_id", nullable = false))
public Collection<PaymentItemData> getPaymentItem()
{
return paymentItem;
}
/**
* Set the property paymentItem
*
* @param value -paymentItem
*
*/
public void setPaymentItem(final Collection<PaymentItemData> value)
{
this.paymentItem = value;
}
}
When i run a query to retrieve records from the payment table in the database, like
Query q = manager.createQuery("select a from PaymentData a");
q.getResultList();
If i allow the fetch=FetchType.EAGER
on the @ManyToMany
, I get the following errors
Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:94)
at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:119)
at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:71)
at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:54)
at org.hibernate.loader.entity.BatchingEntityLoader.createBatchingEntityLoader(BatchingEntityLoader.java:133)
at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(AbstractEntityPersister.java:1914)
at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(AbstractEntityPersister.java:1937)
at org.hibernate.persister.entity.AbstractEntityPersister.createLoaders(AbstractEntityPersister.java:3205)
at org.hibernate.persister.entity.AbstractEntityPersister.postInstantiate(AbstractEntityPersister.java:3191)
at org.hibernate.persister.entity.SingleTableEntityPersister.postInstantiate(SingleTableEntityPersister.java:728)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:348)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1845)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:906)
... 39 more
But if i remove fetch=FetchType.EAGER
and leave it as @ManyToMany
, i will have the exception
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.data.PaymentData.paymentItem, 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.initialize(AbstractPersistentCollection.java:368)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)
at org.hibernate.collection.PersistentBag.toString(PersistentBag.java:506)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at com.niu.util.Util.toString(Util.java:131)
at com.niu.util.data.BaseData.toString(BaseData.java:107)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at java.util.AbstractCollection.toString(AbstractCollection.java:422)
at java.lang.String.valueOf(String.java:2826)
at java.io.PrintStream.println(PrintStream.java:771)
at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:269)
at sun.reflect.GeneratedMethodAccessor1861.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:452)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:291)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:254)
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:133)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:207)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:207)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:190)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:94)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.niu.web.common.interceptor.ApplicationModelDrivenInterceptor.intercept(ApplicationModelDrivenInterceptor.java:31)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at org.apache.struts2.interceptor.ProfilingActivationInterceptor.intercept(ProfilingActivationInterceptor.java:104)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:270)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:190)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:498)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
What am i doing wrong
To avoid the MultipleBagFetchException
, instead of using FetchType.EAGER
, try using the @LazyCollection(LazyCollectionOption.FALSE)
as in this example:
@ManyToMany
@LazyCollection(LazyCollectionOption.FALSE)
@JoinTable(name = "payitem_m_assig", joinColumns = @JoinColumn(name = "pay_item_id", nullable = e), inverseJoinColumns = @JoinColumn(name = "minor_pay_item_id", nullable = false))
public Collection<MinorPayItemData> getMinorPaymentItem()
{
return minorPaymentItem;
}
Here is a small description of from the docs:
@LazyCollection: defines the lazyness option on @ManyToMany and @OneToMany associations. LazyCollectionOption can be TRUE (the collection is lazy and will be loaded when its state is accessed), EXTRA (the collection is lazy and all operations will try to avoid the collection loading, this is especially useful for huge collections when loading all the elements is not necessary) and FALSE (association not lazy)
@Fetch: defines the fetching strategy used to load the association. FetchMode can be SELECT (a select is triggered when the association needs to be loaded), SUBSELECT (only available for collections, use a subselect strategy - please refers to the Hibernate Reference Documentation for more information) or JOIN (use a SQL JOIN to load the association while loading the owner entity). JOIN overrides any lazy attribute (an association loaded through a JOIN strategy cannot be lazy).
I hope it helps
The best way is to make the XxxtoMany associations lazy (the default). This way, the collections will only be loaded when needed, or when you tell Hibernate to fetch them eagerly using a query with a join fetch clause. Making them EAGER forces Hibernate to always load them, even when you don't need them.
Of course, if you need them and they are configured as LAZY, they can only be loaded if the session is still open. Once the session is closed, the entity becomes detached, and the collections can't be lazy-loaded anymore. You thus need to initialize them explicitly (by calling a method of the collection, or by invoking Hibernate.initialize(collection)
) before closing the session.
If you really want to keep them eagerly loaded, then only one of them should be a bag (i.e. of type Collection
or List
). The others should be declared as Set
.
Side note: the mapping of the second association is wrong: you're using the same join column twice.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With