我有一个长时间运行的查询,通过 JDBC 对 MySQL 8 数据库运行。我的目标是能够在某些触发器(例如外部信号、数据处理错误等)上退出此查询并取消查询。根据我在 MySQL 论坛上的测试和研究,
statement.cancel()
实际上没有做任何事情。
我怎样才能实现这个目标?除了在单独的连接上调用
KILL <pid>
之外,没有其他方法吗?如果是这样,我可以管理它,但我不明白如何识别长时间运行的查询的确切 PID。有没有可靠的方法?
简而言之,如何使用 MySQL Connector J 按需取消长时间运行的查询?如果可能的话,我真的很感激包含代码的工作示例的链接。
作为参考,这里是一些用 Kotlin 编写的示例代码:
val data = produce<List<Data>> {
db.connection.use { conn ->
conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY).use { stmt ->
stmt.fetchSize = Int.MIN_VALUE
stmt.executeQuery("...").use { rs ->
var batch = mutableListOf<Data>()
while (rs.next()) {
// Handle result set here
val data = Data(
id = rs.getLong("id"),
subAccountId = rs.getInt("sub_account_id")
)
batch.add(data)
if (batch.size >= 100) {
println("Sending batch...")
send(batch)
if (done) {
println("Done, closing...")
close()
break
}
batch = mutableListOf()
}
}
println("Out of loop, cancelling statement")
synchronized(this) { // my lame attempt at cancelling
println("In synchronized")
if (!stmt.isClosed) {
println("Statement is not yet closed") // DOES print
stmt.cancel()
stmt.close()
conn.close() // probably pointless but I tried
}
}
}
println("Out of statement") // does NOT print
}
println("Out of connection") // does NOT print
}
println("End of production...") // does NOT print
}
我可以在控制台中看到“语句尚未关闭”,但除此之外什么也没有。
如果你想杀死它,你应该使用单独的线程。
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
/////////// 1st thread //////////
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT ...");
});
///////////// 2nd thread //////////
future.cancel(true);