【 使用环境 】生产环境 or 测试环境
【 OB or 其他组件 】
【 使用版本 】
【问题描述】清晰明确描述问题
springboot 项目,mybatis,druid连接池,使用MySQL驱动连接OceanBase数据库的时候,怎么设置ob_query_timeout,
目前长时间查询超时,报错
### Error querying database. Cause: java.sql.SQLException: Timeout, query has reached the maximum query timeout: 10000000(us), maybe you can adjust the session variable ob_query_timeout or query_timeout hint, and try again.
### Cause: java.sql.SQLException: Timeout, query has reached the maximum query timeout: 10000000(us), maybe you can adjust the session variable ob_query_timeout or query_timeout hint, and try again.
; uncategorized SQLException; SQL state [HY000]; error code [4012]; Timeout, query has reached the maximum query timeout: 10000000(us), maybe you can adjust the session variable ob_query_timeout or query_timeout hint, and try again.; nested exception is java.sql.SQLException: Timeout, query has reached the maximum query timeout: 10000000(us), maybe you can adjust the session variable ob_query_timeout or query_timeout hint, and try again.
目前是在select sql语句中,添加 /*+ QUERY_TIMEOUT(900000000) */ 解决的,想找一个全局的解决方案
目前已经试过的方案有,
1、在url中添加 &queryTimeout=60000000 不起作用;
2、在 application-dev.yml 中设置
spring:
datasource:
druid:
connection-properties: queryTimeout=5000
也不起作用
想找一个方法,可以设置到会话级别的
【复现路径】问题出现前后相关操作
【附件及日志】推荐使用OceanBase敏捷诊断工具obdiag收集诊断信息,详情参见链接(右键跳转查看):
【SOP系列 22 】——故障诊断第一步(自助诊断和诊断信息收集)
【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手 ] 即可召唤小助手,欢迎试用!
1 个赞
论坛小助手
2025 年4 月 7 日 12:54
#3
根据文档库中的信息,以下是关于如何在 SpringBoot 项目中使用 MyBatis 和 Druid 连接池连接 OceanBase 数据库时设置 ob_query_timeout
的解决方案:
问题分析
从错误日志来看,当前查询超时时间被限制为 10,000,000 微秒(即 10 秒),导致长时间运行的查询失败。您已经在 SQL 中通过 Hint 设置了 QUERY_TIMEOUT
,但希望找到一个全局的解决方案。
目前尝试过的方案包括:
在 JDBC URL 中添加 &queryTimeout=60000000
。
在 application-dev.yml
中通过 spring.datasource.druid.connection-properties: queryTimeout=5000
设置。
然而,这些方法均未生效。
解决方案
方法一:通过会话变量设置 ob_query_timeout
您可以使用以下方式在程序启动时设置全局的 ob_query_timeout
值。
修改 MyBatis 配置文件
在 MyBatis 的 jdbc.properties
文件中,添加初始化 SQL 脚本以设置会话级别的 ob_query_timeout
。例如:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:oceanbase://10.10.10.1:2881/test?useSSL=false&useUnicode=true&characterEncoding=utf-8
jdbc.username=root@mysql001
jdbc.password=******
jdbc.initSql=SET SESSION ob_query_timeout = 900000000;
其中,jdbc.initSql
是用于在每次连接建立后执行的初始化 SQL。这里将 ob_query_timeout
设置为 900,000,000 微秒(即 900 秒)。
确保 Druid 支持初始化 SQL
在 application-dev.yml
中配置 Druid 连接池支持初始化 SQL:
spring:
datasource:
druid:
connection-properties: initSql=SET SESSION ob_query_timeout = 900000000;
方法二:通过租户级别设置 ob_query_timeout
如果希望对整个租户生效,可以设置租户级别的 ob_query_timeout
。可以通过以下 SQL 执行:
SET GLOBAL ob_query_timeout = 900000000;
注意 :此操作需要管理员权限,并且会影响该租户下的所有会话。
方法三:检查驱动兼容性
确保使用的 MySQL 驱动版本与 OceanBase 数据库兼容。根据文档片段,推荐使用 com.mysql.cj.jdbc.Driver
作为数据库驱动。
方法四:验证连接池配置
根据文档片段《数据库连接规范》,建议检查以下连接池配置项:
连接超时时间 :设置为 1 秒。
最大空闲时间 :设置为 3600 秒。
失败重连机制 :确保连接失败时具备重连功能。
在 application-dev.yml
中配置如下:
spring:
datasource:
druid:
max-wait: 1000 # 连接等待超时时间,单位毫秒
initial-size: 5 # 初始连接数
min-idle: 5 # 最小空闲连接数
max-active: 20 # 最大活跃连接数
time-between-eviction-runs: 60000 # 检测连接是否空闲的时间间隔,单位毫秒
min-evictable-idle-time: 300000 # 连接保持空闲而不被驱逐的最小时间,单位毫秒
总结
SQL 级别 :通过 Hint 设置 /*+ QUERY_TIMEOUT(900000000) */
。
会话级别 :通过 SET SESSION ob_query_timeout = 900000000;
设置。
租户级别 :通过 SET GLOBAL ob_query_timeout = 900000000;
设置。
连接池配置 :确保 Druid 连接池正确配置并支持初始化 SQL。
以上方法可以有效解决长时间查询超时的问题。如果仍有问题,请进一步检查驱动版本和数据库配置是否兼容。
更多信息请查看:
阅读和管理 OceanBase 数据库 SQL 执行计划
SpringBoot 连接 OceanBase 数据库示例程序
Druid 连接池连接 OceanBase 数据库示例程序
MyBatis 连接 OceanBase 数据库示例程序
数据库连接规范
1 个赞
辞霜
2025 年4 月 7 日 13:59
#4
设置全局变量试试
set global ob_query_timeout=100000000000;
1 个赞
你好,这个肯定是可以的,但是客户的数据库,不好这样直接操作,想看下是否可以设置每次会话呢
论坛小助手
2025 年4 月 7 日 14:17
#6
根据文档库中的信息,以下是关于如何在每次会话中设置 ob_query_timeout
的解决方案,特别适用于您提到的客户数据库场景,避免直接修改租户级别的配置。
解决方案:每次会话设置 ob_query_timeout
方法一:通过初始化 SQL 设置会话变量
您可以利用数据库连接池(如 Druid)的初始化 SQL 功能,在每次建立新连接时自动执行 SET SESSION ob_query_timeout
命令。这样可以确保每个会话都使用指定的超时时间。
配置 Druid 连接池的初始化 SQL
在 Spring Boot 的 application-dev.yml
文件中,添加以下配置:
spring:
datasource:
druid:
connection-init-sql: SET SESSION ob_query_timeout = 900000000;
说明 :connection-init-sql
是 Druid 提供的一个配置项,用于在每次创建新连接时执行初始化 SQL。
验证初始化 SQL 是否生效
您可以通过以下方式验证初始化 SQL 是否成功执行:
在程序中打印日志,确认每次获取连接时是否执行了 SET SESSION ob_query_timeout
。
或者通过 OCP 或其他监控工具查看会话变量的值。
方法二:通过 MyBatis 插件动态设置会话变量
如果您希望更灵活地控制 ob_query_timeout
的设置,可以使用 MyBatis 插件在每次查询前动态设置会话变量。
创建 MyBatis 插件
编写一个 MyBatis 插件,在每次执行 SQL 查询之前设置 ob_query_timeout
:
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class ObQueryTimeoutInterceptor implements Interceptor {
private static final String SET_TIMEOUT_SQL = "SET SESSION ob_query_timeout = 900000000;";
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取当前连接
Executor executor = (Executor) invocation.getTarget();
Connection connection = executor.getTransaction().getConnection();
// 执行设置 ob_query_timeout 的 SQL
try (Statement statement = connection.createStatement()) {
statement.execute(SET_TIMEOUT_SQL);
}
// 继续执行原始查询
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 可以通过 properties 动态设置 timeout 值
}
}
注册插件
在 MyBatis 配置文件中注册该插件:
<plugins>
<plugin interceptor="com.example.ObQueryTimeoutInterceptor"/>
</plugins>
优点
该方法可以在不修改 JDBC URL 或 Druid 配置的情况下,动态设置会话变量。
更加灵活,适合复杂的业务场景。
方法三:通过 Hint 动态设置查询超时时间
如果无法通过会话变量全局设置 ob_query_timeout
,也可以在每条 SQL 中通过 Hint 动态设置查询超时时间。例如:
SELECT /*+ QUERY_TIMEOUT(900000000) */ * FROM your_table WHERE condition;
注意 :此方法需要在每条 SQL 中手动添加 Hint,可能不适合大规模使用。
总结
推荐方法 :通过 Druid 的 connection-init-sql
配置项,在每次会话建立时自动设置 ob_query_timeout
。
灵活方法 :使用 MyBatis 插件动态设置会话变量。
备用方法 :在每条 SQL 中通过 Hint 设置查询超时时间。
以上方法均可以在不修改租户级别配置的情况下,实现每次会话的 ob_query_timeout
设置。如果仍有问题,请进一步检查连接池和驱动版本的兼容性。
详情请参考:
enable_sql_plan_monitor
系统变量总览
列存 FAQ
诊断分析
enable_sql_extension
SQL FAQ
(小助手的答复已结束,如未能解决您的问题,请继续提问并等待其他同学的回复,谢谢!)
菜鸟收割机
2025 年4 月 7 日 14:36
#8
&sessionVariables=ob_query_timeout=xxxxxxx
1 个赞