java - Hibernate 未在新线程 {org.hibernate.exception.GenericJDBCException: could not extract ResultSet} 中从数据库加载数据
问题描述
我正在使用带有休眠功能的弹簧靴。当我尝试在新线程中加载数据(来自 PostgreSQL)时,hibernate 给出了一个异常。但是,如果我在单个线程中执行代码,它工作正常。下面是这个的片段。
客户.java
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(cascade=CascadeType.ALL)
private List<UserEntity> entityList = new ArrayList<UserEntity>();
}
用户实体.java
@Entity
public class UserEntity {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Customer customer;
}
服务层
public class EmailServiceImpl {
public void someFunction() {
Customer cus = customerRepo.findOne(1l);
new Thread(() -> {
cus.getEntityList().isEmpty(); // Below mentioned exception is pointing to this line
// executing some operations based on the size of above list
}).start();
}
}
尝试执行上述方法时出现异常/错误
org.hibernate.exception.GenericJDBCException: could not extract ResultSet
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:434) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:186) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:121) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:88) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:688) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1991) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:570) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:252) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection$1.doWork(AbstractPersistentCollection.java:164) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection$1.doWork(AbstractPersistentCollection.java:149) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:252) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:148) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.collection.internal.PersistentBag.isEmpty(PersistentBag.java:266) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at com.e2log.service.impl.EmailServiceImpl.lambda$3(EmailServiceImpl.java:505) ~[classes/:na]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_161]
Caused by: org.postgresql.util.PSQLException: This statement has been closed.
at org.postgresql.jdbc.PgStatement.checkClosed(PgStatement.java:649) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgStatement.getMaxRows(PgStatement.java:485) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgStatement.createResultSet(PgStatement.java:158) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgStatement$StatementResultHandler.handleResultRows(PgStatement.java:210) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2092) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:288) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:430) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:356) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:168) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:116) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
at sun.reflect.GeneratedMethodAccessor144.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161]
at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114) ~[tomcat-jdbc-8.5.27.jar:na]
at com.sun.proxy.$Proxy215.executeQuery(Unknown Source) ~[na:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
正在执行代码但不适合我的场景
- 单线程执行(即注释/删除 2 行
new Thread(() -> {
和}).start();
) - 急切地加载数据(即将行更改
@OneToMany(cascade=CascadeType.ALL)
为@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
inCustomer.java
)- 写行
cus.getEntityList().isEmpty();
或cus.getEntityList().size();
行上new Thread(() -> {
。(如果我们试图在新线程启动 iof 之前找到大小,我认为休眠正在加载数据)
- 写行
有没有办法让并发代码工作,而不使用急切加载?
仅供参考,Spring 引导版本:1.5.10.RELEASE Java:1.8 PostgreSQL:9.5
解决方案
Spring 使用的事务上下文存储在线程局部变量中。因此,如果您启动一个新线程,或使用可调用对象在另一个线程中执行代码,则此代码不会成为 Spring 事务方面启动的事务的一部分。
相反,如果您想使用从数据库中提取的一些数据来处理异步内容,那么您应该首先将数据库中的数据加载到变量中,然后将加载的数据传递给异步线程以进行进一步处理。
推荐阅读
- python - 贝叶斯优化的最大维度 (GPyOpt, GPFlow)
- r - 如何使用带有 R 的正则表达式在文本文件中列出发现的结果?
- c# - ExecuteScalar 和 ExecuteNonQuery 冲突
- javascript - Angular 7使用授权从服务器启动浏览器文件下载
- hyperledger-fabric - 不支持的配置类型“”
- angular6 - 路由器导航附加组件而不是 relpace 组件
- android - 为什么我的通知栏在空闲后尝试重新制作时消失了?
- flutter - 如何在颤动中打开系统特定的默认应用程序?
- javascript - Jquery在键入时更改输入类
- php - 尊重验证特定字段的可选输入数组