Spring JpaRepository findAll,Java 8 Stream,连接已被放弃

3
我正在使用Spring Boot,并尝试在我的存储库中执行一个findAll查询,该查询应返回结果流:
public interface MyThingRepository extends JpaRepository<MyThing, String> {
   Stream<MyThing> findAll();
}

public class MyScheduledJobRunner {

   @Autowired 
   private MyThingRepository myThingRepository;

   public void run() {
      try (Stream<MyThing> myThingsStream : myThingRepository.findAll()) {
        myThingsStream.forEach(myThing -> {
           // do some stuff
        });
        // myThingsStream.close(); // <- at one point even tried that, though the stream is wrapped in an auto-closing block. anyway, it did not help
       System.out.println("All my things processed.");
     }
     System.out.println("Exited the auto-closing block.");
   }
}

我得到的输出是:

All my things processed.
Exited the auto-closing block.
o.a.tomcat.jdbc.pool.ConnectionPool      : Connection has been abandoned PooledConnection[com.mysql.jdbc.JDBC4Connection@2865b7d5]:java.lang.Exception
|   at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:1061)
...
at MyScheduledJobRunner.run(MyScheduledJobRunner:52) 

MyScheduledJobRunner:52是:

try (Stream<MyThing> myThingsStream : myThingRepository.findAll()) {

根据文档,在使用JpaRepositories中的Streams时,您应该在使用后始终关闭它们。由于它们实现了AutoCloseable接口,因此可以使用try with resources块。 http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-streaming 一个Stream可能包装底层数据存储特定资源,因此必须在使用后关闭。您可以使用close()方法手动关闭Stream,也可以使用Java 7的try-with-resources块。
文档甚至有一个示例,完全与我所做的方式相同。因此,据我所知,我正在按照文档上的所有说明操作,但仍然在操作后30秒后出现异常。因此,连接未关闭并保持挂起状态。为什么会这样,我该如何克服呢?
我已尝试使用Postgres 9.5和MariaDB作为数据库。我正在使用最新可能的连接器/驱动程序和Tomcat连接池,该连接池通过spring boot的属性进行配置,如下:
spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost/mydb?useSSL=false
    username: user
    password: password
    initial-size: 10
    max-active: 100
    max-idle: 50
    min-idle: 10
    max-wait: 15000
    test-while-idle: true
    test-on-borrow: true
    validation-query: SELECT 1
    validation-query-timeout: 5
    validationInterval: 30000
    time-between-eviction-runs-millis: 30000
    min-evictable-idle-time-millis: 60000
    removeAbandonedTimeout: 60
    remove-abandoned: true
    log-abandoned: true

1
是的。我所有的注释和bean都已设置好。如果它们没有被设置,那么我的数据库操作根本不会工作,但它确实很好地工作了。只有这个让我不喜欢在日志中看到的可恶的废弃连接错误。这只是一个最简单的例子。如果您查看我提供的文档链接,您将看到Spring Boot JPA与Java 8除了Page和Collection之外还支持Stream。我使用Stream而不是Page或Collection的动机是MyThings集合可能非常庞大,我无法将其读入内存。 - Tarmo
1
好的,我会。我也得到了Stream<MyThing>。问题不在于没有得到它,问题在于在读取数据库条目后,数据库连接没有正确关闭。 - Tarmo
我不熟悉Spring JPA,但是Stream<MyThing> findAll()是你实现的方法还是由Spring生成的? - user140547
1
我在我的实际代码中也做了一些像自动装配之类的东西,但这并不重要,因为它只是一个最小化可行示例。 - Tarmo
1
经过一些调试和与Spring Boot开发人员的讨论,我决定在Spring Data的问题跟踪器中创建一个问题:https://jira.spring.io/browse/DATAJPA-917 - Tarmo
显示剩余7条评论
1个回答

0

在连接池配置中,您只需要添加以下内容:

"org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer"


3
请详细说明为什么以及如何使用该属性会对我有所帮助? - Tarmo
你可以在这个链接中找到相关信息:http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency。这个属性重置超时时间。 - kuciB
1
听起来很奇怪,为了使用箱外的Spring功能并以不抛出异常的方式进行良好记录,我必须设置一些随机的Tomcat参数。在这种情况下,最好的情况是文档存在错误。无论如何,我无法使其工作(ClassNotFound)。 - Tarmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接