Двунаправленное отношение OneToMany, приводящее к превышению максимальных открытых курсоров - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть 3 таблицы Foo, Bar и Foo_x_Bar_Status, в моем сервисе я пытаюсь создать новую запись для Foo_x_Bar_Status.Я выбираю управляемый объект Foo и управляемый объект Bar, затем создаю новый объект FooBarStatus и устанавливаю на него ранее выбранные объекты Foo и Bar.Затем я пытаюсь сохранить мой недавно созданный FooBarStatus wirh entityManager.merge() (необходимо выполнить слияние, поскольку мне нужно вернуть управляемый объект FooBarStatus без его повторного поиска), однако это слияние завершается с сообщением: java.sql.SQLException: - ORA-01000: maximum open cursors exceeded, как я могу решить эту проблемупроблема?

PS Я знаю, что могу просто удалить коллекции из Foo и Bar, и доступ осуществляется через выделенный сервис, однако для меня важно иметь это двунаправленное отношение

Foo:

@Entity(name = "Foo")
@Table(name = "FOO")
public class Foo implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FOO_SEQ")
private Long id;

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, mappedBy = "foo", orphanRemoval = true)
private Set<FooBarStatus> fooBarStatus;
}

Бар:

@Entity(name = "Bar")
@Table(name = "BAR")
public class BAR implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BAR_SEQ")
private Long id;

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, mappedBy = "bar", orphanRemoval = true)
private Set<FooBarStatus> fooBarStatus;
}

FooBarStatus:

@Entity(name = "FooBarStatus")
@Table(name = "Foo_x_Bar_Status")
public class FooBarStatus implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FOO_BAR_STATUS_SEQ")
private Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "FOO_ID", nullable = false)
private Foo foo;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "BAR_ID", nullable = false)
private Bar bar;

Сервис

@Service
public class FooBarStatusServiceImpl implements FooBarStatus {

@Autowired
private FooRepository fooRepository;

@Autowired
private BarRepository barRepository;

@Autowired
private FooBarStatusReposiotry fooBarStatusReposiotry;

@Override
public FooBarStatus createFooBarStatus(Foo foo, Bar bar) {
//make foo nd bar managed
foo = fooRepository.createFoo(foo);
bar = barRepository.createBar(bar);

FooBarStatus fooBarStatus = new FooBarStatus();
fooBarStatus.setFoo(foo);
fooBarStatus.setBar(bar);

return fooBarStatusReposiotry.createFooBarStatus(fooBarStatus);
}
}

FooBarStatusReposioty:

@Repository
public class FooBarStatusReposiotyImpl implements FooBarStatusReposioty {

    @PersistenceContext
    public EntityManager entityManager;

@Override
public FooBarStatus createFooBarStatus(FooarStatus fooBarStatus){
    return entityManager.merge(fooBarStatus);
}
}

Stacktrace:

2018-11-28 16:43:02 ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet] with root cause
java.sql.SQLException: ORA-01000: maximum open cursors exceeded

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1059)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:522)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:587)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:225)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:53)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:774)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:925)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1111)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:4798)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:4845)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1501)
at sun.reflect.GeneratedMethodAccessor154.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
at com.sun.proxy.$Proxy119.executeQuery(Unknown Source)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:434)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:186)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:121)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:88)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:688)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1991)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:570)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:252)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:430)
at com.iwork.server.defautmodel.User.hashCode(User.java:20)
at com.iwork.server.defautmodel.UserNotification.hashCode(UserNotification.java:11)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:327)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:234)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:221)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:194)
at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:249)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:212)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:88)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:688)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1991)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:570)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:252)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:430)
at com.application.server.defautmodel.Bar.hashCode(Bar.java:20)
at com.application.server.defautmodel.Foo.hashCode(Foo.java:11)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)

трассировка стека намного длиннее, но кажется, что она зацикливается.Foo.java:11 и Bar.java:20 указывают на аннотацию @Data от Lombok

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Как предложено @Chris в комментарии, основной причиной было то, что использование аннотации @Data сгенерировало метод вычисления HashCode, и поскольку Foo, Bar и FooBarStatus имели ленивые инициализированные атрибуты с двунаправленным отношением, вычисление хеша пыталось получить данные и откатилось назад.бесконечно.Так как все Foo, Bar и FooBarStatus уникальны по идентификаторам, нет необходимости включать объединенные атрибуты в вычисление хеша.Поэтому согласно https://projectlombok.org/features/EqualsAndHashCode я добавил @ EqualsAndHashCode.Exclude к двунаправленным ленивым инициализированным атрибутам, которые исключили вычисление из хеша.Пример ниже:

@Entity(name = "Foo")
@Table(name = "FOO")
public class Foo implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FOO_SEQ")
private Long id;

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, mappedBy = "foo", orphanRemoval = true)
@EqualsAndHashCode.Exclude
private Set<FooBarStatus> fooBarStatus;
}
0 голосов
/ 28 ноября 2018

Эта ошибка вызвана тем, что Connections, Statements и ResultSets оставлены открытыми.Пример,

Connection with = getConnection();
PreparedStatement ps = con.prepareStatement 
ResultSet rs = ps.executeQuery ();

Итак, вы просто закрываете опцию

rs.close ();
ps.close ();
con.close ();

, чтобы использовать try {} catch (e) {} finally {} и закройте в finally

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...