简体   繁体   中英

Hibernate: java.lang.StackOverflowError while trying to persist an object graph

I'm stuck while trying to persist a many-to-one relationship in the database. My approach seems logic to me, but hibernate hits my face with a java.lang.StackOverflowError . Let me illustrate the starting situation:

帐户与人的关系

Account and Person records have already been persisted in the databse, however Account and Person still have to be linked together through a statement like account.setPerson(person); I tried the following code. Let me introduce you into the code step by step.

Open a session:

Session session = sessionFactory.openSession();
session.beginTransaction();

Query all accounts with a to_attribute. This attribute is used to link with a source attribute in person called from_attribute. These attributes are fetched from an xml config file and serve as a basis to define the foreign key relationship.

List<Account> queried_accounts = HibernateUtils.queryList(
                    session.createQuery(""
                            + "select distinct acc from Account as acc"
                            + " inner join acc.accountAttributes as accAtt"
                            + " inner join accAtt.aa_pk.attribut as attr"
                            + " where attr.name='" + to_attribute + "'")
            );

Query all persons

List<Person> queried_persons = HibernateUtils.queryList(session.createQuery("from Person"));

Link together all accounts with a matching person. A person matches, if the value in his from_attribute is equal to the value of the to_attribute in account. I suppose that this piece of code causes a StackOverflow, but im not sure why. First, i thought its due to the fact, that many objects are altered before session.getTransaction().commit() . But even session.flush() didn't do the trick. I know, this code isnt very smart. It causes "Amount of Account records" x "Amount of person records" read operations plus the same amount for equal checks. So, its a runtime complexity of O(n^2). Correct me, if im wrong.

for (Account account : queried_accounts) {
                String account_to_attribut_wert = account.getAttributeValue(to_attribute);
                for (Person person : queried_persons) {
                    if (person.getAttributeValue(from_attribute).equals(account_to_attribut_wert)) {
                        account.setPerson(person);
                        // session.flush();
                    }
                }

            }

session.getTransaction().commit();
session.close();

So, can you help me out with that? I dont know how to avoid the StackOverflowError

Here is the stack trace (this trace is long, but contains always the same text).

java.lang.StackOverflowError at org.hibernate.internal.SessionImpl.getLoadQueryInfluencers(SessionImpl.java:2071) at org.hibernate.engine.spi.QueryParameters.processFilters(QueryParameters.java:481) at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:188) at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:137) at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102) at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186) at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4120) at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:502) at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:467) a t org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:212) at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:274) at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150) at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1066) at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:985) at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:673) at org.hibernate.type.EntityType.resolve(EntityType.java:489) at org.hibernate.type.ComponentType.resolve(ComponentType.java:668) at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.resolveEntityKey(EntityReferenceInitializerImpl.java:158) at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.resolveEntityKey(AbstractRowReader.java:148) at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.readRow(AbstractRowReader.java:97 ) at org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:255) at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:129) at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138) at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102) at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186) at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4120) at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:502) at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:467) at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEvent Listener.java:212) at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:274) at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150) at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1066) at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:985) at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:673) at org.hibernate.type.EntityType.resolve(EntityType.java:489) at org.hibernate.type.ComponentType.resolve(ComponentType.java:668)

I believe only reason that cause this might be recursive call. You should definitely try to remove those recursive call, but for your question try to set your query's flush mode to FlushModeType.COMMIT.

Since it's due to StackOverflow, you might also able to increase stack size with Xss JVM option if you have to use that recursive call anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM