Java 导致超过最大打开游标数的双向OneToMany关系

Java 导致超过最大打开游标数的双向OneToMany关系,java,hibernate,jpa,spring-data-jpa,Java,Hibernate,Jpa,Spring Data Jpa,我有三个表Foo,Bar和Foo_x_Bar_状态,在我的服务中,我试图为Foo_x_Bar_状态创建新记录。我正在获取Foo的托管对象和Bar的托管对象,然后创建FooBarStatus的新对象,并在其上设置以前获取的Foo和Bar对象。然后,我尝试将我新创建的FooBarStatus与RH entityManager.merge进行合并,因为我需要返回FooBarStatus托管对象,而无需再次搜索它,但是此合并失败,消息为:java.sql.SQLException:-ORA-01000:

我有三个表Foo,Bar和Foo_x_Bar_状态,在我的服务中,我试图为Foo_x_Bar_状态创建新记录。我正在获取Foo的托管对象和Bar的托管对象,然后创建FooBarStatus的新对象,并在其上设置以前获取的Foo和Bar对象。然后,我尝试将我新创建的FooBarStatus与RH entityManager.merge进行合并,因为我需要返回FooBarStatus托管对象,而无需再次搜索它,但是此合并失败,消息为:java.sql.SQLException:-ORA-01000:超过最大打开游标数,我如何解决此问题

另外,我知道我可以从Foo和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);
}
}
堆栈跟踪:

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)
stacktrace长得多,但看起来像是在循环。
Foo.java:11和Bar.java:20指向Lombok中的@Data annotation

此错误是由打开的连接、语句和结果集引起的。例如

Connection with = getConnection();
PreparedStatement ps = con.prepareStatement 
ResultSet rs = ps.executeQuery ();
所以,你只需关闭

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

选项是使用try{}catch e{}finally{}并在finally

中关闭,正如@Chris在comment中建议的那样,根本原因是使用@Data注释生成了一个HashCode计算方法,并且由于Foo、Bar和FooBarStatus具有双向关系的惰性初始化属性,散列计算试图获取数据,但被无限次删除。由于所有的Foo、Bar和FooBarStatus都是唯一的id,所以在散列计算中不必包含连接属性。因此,根据,我已将@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;
}

在hibernate的情况下,您必须关闭会话,才能通过依赖项注入(如EJB和@PersistenceContext注释)获得实体管理器,还是使用EntityManagerFactory?如果使用注释,则不应发生这种情况。@Alanjone如何做到这一点?我以为是@Transactional处理的annotation@AkkaJaworek我正在使用org.hibernate.Session,请尝试在持久性类中执行此操作:public void saveOuUpdate Object obj{Session Session Session=getSession;Session.saveOrUpdate obj;Session.flush;Session.clear;}首先,每个实体都必须有一个ID,而FooBarStatus没有。其次,使用entityManager.persist,它使实例得到管理和持久化。因此,您不必再次查询。修复这些基本问题,看看你在哪里。@AlanHay Foo和Bar是我的类的简化版本,只是为了表示问题,当然它们有Id。请提供一些上下文,说明在这种情况下为什么persist与merge的工作方式不同?好像是瞎开枪对不起,我猜不出是怎么回事。为什么不发布所有相关代码并正确使用API作为第一步。@AlanHay在repository中添加了完整代码,将merge更改为Persiste,但并没有解决问题。看起来您正在使用hashcode方法进行一些奇怪的操作,导致触发了一大堆查询。您似乎在Bar、foo和UserNotification以及用户类上这样做。不要在hashcode或相等性检查中访问lazy或任何关系,尤其是在使用映射或使用它们的集合时。
Connection with = getConnection();
PreparedStatement ps = con.prepareStatement 
ResultSet rs = ps.executeQuery ();
rs.close ();
ps.close ();
con.close ();
@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;
}