Ale*_*nov 7 hibernate spring-data spring-data-jpa java-stream
这是一个存储库,其中包含此问题中的代码,其中包含错误:https: //github.com/agsimeonov/stream-bug
我一直在尝试使用以下代码片段使用Spring Data JPA和Hibernate来传输查询结果(data.txt是一个3000行的文件,每行都有一个数字):
try (Stream<Customer> stream = repository.streamAll()) {
stream.forEach(customer -> {
try {
File data = new File(getClass().getClassLoader().getResource("data.txt").getFile());
try (BufferedReader reader = new BufferedReader(new FileReader(data))) {
while (reader.readLine() != null) {
// Do stuff for the current customer
}
}
} catch (IOException e) {}
System.out.println(customer);
});
}
Run Code Online (Sandbox Code Playgroud)
这是域对象:
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
public Customer() {}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
}
}
Run Code Online (Sandbox Code Playgroud)
这是存储库:
public interface CustomerRepository extends JpaRepository<Customer, Long> {
@Query("SELECT c FROM Customer c")
Stream<Customer> streamAll();
}
Run Code Online (Sandbox Code Playgroud)
执行此操作会导致以下错误:
org.hibernate.exception.GenericJDBCException: could not advance using next()
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
at org.hibernate.internal.ScrollableResultsImpl.convert(ScrollableResultsImpl.java:69)
at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:104)
at org.springframework.data.jpa.provider.PersistenceProvider$HibernateScrollableResultsIterator.hasNext(PersistenceProvider.java:454)
at java.util.Iterator.forEachRemaining(Iterator.java:115)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at stream.bug.StreamBugApplication.lambda$0(StreamBugApplication.java:34)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:784)
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:771)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175)
at stream.bug.StreamBugApplication.main(StreamBugApplication.java:22)
Caused by: org.h2.jdbc.JdbcSQLException: The object is already closed [90007-193]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.message.DbException.get(DbException.java:144)
at org.h2.jdbc.JdbcResultSet.checkClosed(JdbcResultSet.java:3202)
at org.h2.jdbc.JdbcResultSet.next(JdbcResultSet.java:129)
at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:99)
... 12 more
Run Code Online (Sandbox Code Playgroud)
我花了很多时间调试这个,我终于设法创建了一个小的spring-boot示例应用程序,展示了流错误:https: //github.com/agsimeonov/stream-bug
我肯定知道一些事情:
首先 - 这个bug与底层数据库无关.虽然我在示例项目中使用H2,但我尝试使用Postgres,但是仍然会出现一个非常类似的错误,请注意我在其他项目中使用tomcat连接池,我尝试过不同的连接池,所以它绝对不是连接池或导致此问题的底层数据库.这是一个带有postgres和tomcat连接池的示例跟踪,您可能会注意到它非常相似:
org.hibernate.exception.GenericJDBCException: could not advance using next()
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.internal.ScrollableResultsImpl.convert(ScrollableResultsImpl.java:69)
at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:104)
at org.springframework.data.jpa.provider.PersistenceProvider$HibernateScrollableResultsIterator.hasNext(PersistenceProvider.java:454)
at java.util.Iterator.forEachRemaining(Iterator.java:115)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at com.trove.sunstone.attributefusion.services.impl.PhysicalServiceImpl.match(PhysicalServiceImpl.java:130)
at com.trove.sunstone.attributefusion.AppRunner.main(AppRunner.java:31)
Suppressed: java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy238.hashCode(Unknown Source)
at java.util.HashMap.hash(HashMap.java:338)
at java.util.HashMap.get(HashMap.java:556)
at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.release(ResourceRegistryStandardImpl.java:76)
at org.hibernate.internal.AbstractScrollableResults.close(AbstractScrollableResults.java:104)
at org.springframework.data.jpa.provider.PersistenceProvider$HibernateScrollableResultsIterator.close(PersistenceProvider.java:465)
at org.springframework.data.util.StreamUtils$CloseableIteratorDisposingRunnable.run(StreamUtils.java:96)
at java.util.stream.AbstractPipeline.close(AbstractPipeline.java:323)
at com.trove.sunstone.attributefusion.services.impl.PhysicalServiceImpl.match(PhysicalServiceImpl.java:137)
... 1 more
Caused by: java.sql.SQLException: Statement closed.
at org.apache.tomcat.jdbc.pool.interceptor.AbstractQueryReport$StatementProxy.invoke(AbstractQueryReport.java:224)
... 10 more
Caused by: org.postgresql.util.PSQLException: This ResultSet is closed.
at org.postgresql.jdbc.PgResultSet.checkClosed(PgResultSet.java:2740)
at org.postgresql.jdbc.PgResultSet.next(PgResultSet.java:1817)
at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:99)
... 11 more
Run Code Online (Sandbox Code Playgroud)
第二个 - 奇怪的是,从流中的forEach()中删除以下行会导致流正确完成.这让我相信它可能是某种时间问题,但是我试图用Thread.sleep()而不是文件读取来复制它而没有成功.作为旁注,data.txt是一个包含3000行的文件,每行都有一个数字.
try {
File data = new File(getClass().getClassLoader().getResource("data.txt").getFile());
try (BufferedReader reader = new BufferedReader(new FileReader(data))) {
while (reader.readLine() != null) {
// Do stuff for the current customer
}
}
} catch (IOException e) {}
Run Code Online (Sandbox Code Playgroud)
第三 - 更换:
Stream<Customer> stream = repository.streamAll()
Run Code Online (Sandbox Code Playgroud)
附:
Stream<Customer> stream = repository.findAll().stream()
Run Code Online (Sandbox Code Playgroud)
修复了这个问题所以这肯定是流和/或ScrollableResults的错误,因为将所有数据加载到列表中会使应用程序完成没有错误,但是对于我当前的项目,我需要直接使用Streams,因此使用findAll()不是选项.
如果有人遇到此问题并能够修复它,请告诉我.另外,请随时检查,分叉和/或更改提供的存储库中的代码,这有助于解决此问题.我已经创建了这个项目作为演示,应该用来说明这个bug.
我在Spring Data JPA JIRA上发布了我的问题作为错误报告,之前显然已经发现了这个问题.经过一些讨论后,我现在在Stream相关代码上使用@Transactional来解决问题作为一种解决方法.感谢Oliver Gierke在此指出:https://jira.spring.io/browse/DATAJPA-989?focusCommentId = 133710&page = com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-133710
我已经将解决方案推送到最近提交到我的示例错误存储库中的错误:https: //github.com/agsimeonov/stream-bug/commit/9da536d0a9d921787f6d2d4d75720d363ba0358b
| 归档时间: |
|
| 查看次数: |
5212 次 |
| 最近记录: |