【问题标题】:Database query interruption数据库查询中断
【发布时间】:2017-01-05 11:09:26
【问题描述】:

我已经在新线程中启动了一些进程:

FutureTask<?> futureTask = new FutureTask<Void>(() -> {
               startSomeProcess();
            }, null);

startSomeProcess 方法中,我为每个项目生成报告:

for (Item item : items) {
            if (Thread.interrupted()) {
                logger.info("currentThread isInterrupted");
                return;
            }
             generateReport(item);
     }

generateReport() 方法中,我对DB 执行一些选择并从ResultSet 生成excel 报告:

try (PreparedStatement ps = conn.prepareStatement(query.toString(),
                    ResultSet.TYPE_SCROLL_INSENSITIVE)) {
                ResultSet rs = ps.executeQuery();
                //and fill excel from rs 
                 ...

但是我的ps.executeQuery(); 可以执行很长时间(1 sec- 999999h. 我有取消按钮。如果它按我做这个

futureTask.cancel(true); 

并检查startSomeProcess(); 方法中的异常。但我无法检查和中断ps.executeQuery();。当我使futureTask.cancel(true); 这个executeQuery 抛出异常时。但我没有配置这个。它是自动的。

我的问题:当我中断线程时 - 我是否可以或是否让自己中断对数据库的查询,或者它只是发生并且我必须只处理错误?

编辑:

用户发送命令 - “取消报告生成”。我找到 futureTask 并调用 cancel() 方法。并打破构建报告。但是如果 ps.executeQuery();已经开始了——不知道怎么破

【问题讨论】:

    标签: java multithreading interrupt spring-jdbc futuretask


    【解决方案1】:

    我的问题:当我中断线程时 - 我是否可以让自己中断对数据库的查询,或者它只是发生并且我必须只处理错误?

    中断线程只会在线程上设置一个标志,这只会导致那些抛出InterruptedException的方法这样做。在这种情况下,SQL 方法不会抛出 InterruptedException,因此仅调用 future.cancel(true) 将不起作用。

    如果您尝试取消正在运行的 SQL 查询,那么您将需要 canceling the underlying Statement 在 JDBC 级别执行此操作。引用Statement.cancel()的javadocs:

    如果 DBMS 和驱动程序都支持中止 SQL 语句,则取消此 Statement 对象。这个方法可以被一个线程用来取消另一个线程正在执行的语句。

    所以在你的情况下,这意味着另一个线程将不得不取消你的ps。我将创建一个对象来包装您的 generateReport() 方法,该方法将 PreparedStatement ps 放入 volatile 字段中。然后,当该方法执行ps 时,它会从字段中执行此操作,并且另一个线程可以在调用ps.cancel() 的对象上调用cancel()

    请务必注意,查询取消取决于 SQL 数据库和 JDBC 驱动程序。并非所有数据库都支持它。

    【讨论】:

      【解决方案2】:

      当我中断线程时 - 我是否可以或是否让自己中断对数据库的查询,或者它只是发生并且我必须只处理错误?

      一旦executeQuery启动,可以使用cancel方法停止。

      其他方式是处理异常或使用setQueryTimeout

      【讨论】:

      • 如果控制器放置了控制器->新线程->第一个服务->第二个服务->PreparedStatement对象,我如何在控制器中获取PreparedStatement对象
      • 使用 setQueryTimeout - 是不好的解决方案。我可以有很大的查询。我只需要在用户按下按钮时停止执行
      • @user5620472 你也需要设计取消服务。
      • @user5620472 setQueryTimeout 我建议以一般方式取消查询,而不是特定于您的问题,以便您可以考虑使用它,如果它可以适合您的设计而几乎没有改变.
      • 我正在谈论它并询问。我实现了执行线程的中断。如果线程被中断 - 我打破我的循环并返回。但我无法理解如何获得 PreparedStatement 并调用 cancel() 方法
      猜你喜欢
      • 2014-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-03
      • 2017-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多