本文主要是介绍h2 数据库Statement was canceled or the session timed out 解决办法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
背景
某项目因需要存储的数据较少,选择了h2 数据库。数据库的某张表的数据需要全部加载到内存中使用。
最近,某个项目使用该应用时需求比较特殊,使得这张表的数据量增加到了一万条。此时,查询全量数据的 SQL 发生了异常:
org.h2.jdbc.JdbcSQLException: Statement was canceled or the session timed out; SQL statement:
SELECT xxx [57014-197]
解决办法
什么是Statement Timeout?
statement timeout用来限制statement的执行时长,timeout的值通过调用JDBC的java.sql.Statement.setQueryTimeout(int timeout) API进行设置。不过现在开发者已经很少直接在代码中设置,而多是通过框架来进行设置。
原生的 JDBC Statement
类提供了超时时间设置方法 setQueryTimeout
,一万条数据 h2 数据库查询耗时40秒,设置1分钟就可以解决这个异常了。
改为用原生 JDBC 查询,先查询总数,再以总数创建 List,后查询列表添加到 List 中:
// TODO 先查询总数
String countSql = "SELECT count(*) FROM xx WHERE R_ID=?";
if (totalCount == 0) {return Collections.emptyList();}// TODO 查询记录列表
data = new ArrayList<>((int) totalCount);
String sql = "SELECT a,b from xx R_ID=?";stmt = conn.prepareStatement(sql);// 设置连接查询的超时时间,解决过滤规则过大时、规则查询 java.sql.SQLException: Statement was canceled or the session timed out; SQL statement:
stmt.setQueryTimeout(100);
stmt.setObject(1, id);
rs = stmt.executeQuery();// TODO 处理数据
额外尝试
决定因素是什么呢?超时时间配置,还是 fetchSize
呢?
- 两个都加上总时间 52 秒。
- 有超时时间,没有 fetchSize ,45秒回来,也能回来。
- 无超时时间,有 fetchSize ,还是异常。
- 在 Connection 设置 网络超时配置定时任务,
setNetworkTimeout(Executors.newSingleThreadExecutor(), 120000)
无效。
结论:查询语句的超时时间是关键因素,配置 fetchSize
对超时没有影响,但是它影响一次加载的数据量,配置的话可以降低内存、但是增加了查询时间。
启示录
换成 MySQL 数据库后就不存在这个问题了,一次查询2万条毫秒回复。JDBC 各种超时时间的含义,找到一篇比较详细的文章《JDBC超时设置》。
平心而论,h2 是相当轻量的,删除源码等无用文件后,总大小 2M 左右。两兆啊,相比现在动不动就上百M 的 Java 应用来说,这么小体量的 Java 应用,清流一样的存在啊!小而美,两难全吧!
额外测试了:对于稍微大一点的表都有瓶颈,一万条还可以用本文的方法解决,2万条超时时间5分钟都回不来。对于简单应用来说,还是够用的。
这篇关于h2 数据库Statement was canceled or the session timed out 解决办法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!