springboot 项目,mybatis,druid连接池,使用MySQL驱动连接OceanBase数据库的时候,怎么设置ob_query_timeout

【 使用环境 】生产环境 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 个赞

根据文档库中的信息,以下是关于如何在 SpringBoot 项目中使用 MyBatis 和 Druid 连接池连接 OceanBase 数据库时设置 ob_query_timeout 的解决方案:

问题分析

从错误日志来看,当前查询超时时间被限制为 10,000,000 微秒(即 10 秒),导致长时间运行的查询失败。您已经在 SQL 中通过 Hint 设置了 QUERY_TIMEOUT,但希望找到一个全局的解决方案。

目前尝试过的方案包括:

  1. 在 JDBC URL 中添加 &queryTimeout=60000000
  2. application-dev.yml 中通过 spring.datasource.druid.connection-properties: queryTimeout=5000 设置。

然而,这些方法均未生效。


解决方案

方法一:通过会话变量设置 ob_query_timeout

您可以使用以下方式在程序启动时设置全局的 ob_query_timeout 值。

  1. 修改 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 秒)。

  2. 确保 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 # 连接保持空闲而不被驱逐的最小时间,单位毫秒

总结

  1. SQL 级别:通过 Hint 设置 /*+ QUERY_TIMEOUT(900000000) */
  2. 会话级别:通过 SET SESSION ob_query_timeout = 900000000; 设置。
  3. 租户级别:通过 SET GLOBAL ob_query_timeout = 900000000; 设置。
  4. 连接池配置:确保 Druid 连接池正确配置并支持初始化 SQL。

以上方法可以有效解决长时间查询超时的问题。如果仍有问题,请进一步检查驱动版本和数据库配置是否兼容。

更多信息请查看:

  1. 阅读和管理 OceanBase 数据库 SQL 执行计划
  2. SpringBoot 连接 OceanBase 数据库示例程序
  3. Druid 连接池连接 OceanBase 数据库示例程序
  4. MyBatis 连接 OceanBase 数据库示例程序
  5. 数据库连接规范
1 个赞

设置全局变量试试
set global ob_query_timeout=100000000000;

1 个赞

你好,这个肯定是可以的,但是客户的数据库,不好这样直接操作,想看下是否可以设置每次会话呢

根据文档库中的信息,以下是关于如何在每次会话中设置 ob_query_timeout 的解决方案,特别适用于您提到的客户数据库场景,避免直接修改租户级别的配置。


解决方案:每次会话设置 ob_query_timeout

方法一:通过初始化 SQL 设置会话变量

您可以利用数据库连接池(如 Druid)的初始化 SQL 功能,在每次建立新连接时自动执行 SET SESSION ob_query_timeout 命令。这样可以确保每个会话都使用指定的超时时间。

  1. 配置 Druid 连接池的初始化 SQL
    在 Spring Boot 的 application-dev.yml 文件中,添加以下配置:

    spring:
      datasource:
        druid:
          connection-init-sql: SET SESSION ob_query_timeout = 900000000;
    

    说明connection-init-sql 是 Druid 提供的一个配置项,用于在每次创建新连接时执行初始化 SQL。

  2. 验证初始化 SQL 是否生效
    您可以通过以下方式验证初始化 SQL 是否成功执行:

    • 在程序中打印日志,确认每次获取连接时是否执行了 SET SESSION ob_query_timeout
    • 或者通过 OCP 或其他监控工具查看会话变量的值。

方法二:通过 MyBatis 插件动态设置会话变量

如果您希望更灵活地控制 ob_query_timeout 的设置,可以使用 MyBatis 插件在每次查询前动态设置会话变量。

  1. 创建 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 值
        }
    }
    
  2. 注册插件
    在 MyBatis 配置文件中注册该插件:

    <plugins>
        <plugin interceptor="com.example.ObQueryTimeoutInterceptor"/>
    </plugins>
    
  3. 优点

    • 该方法可以在不修改 JDBC URL 或 Druid 配置的情况下,动态设置会话变量。
    • 更加灵活,适合复杂的业务场景。

方法三:通过 Hint 动态设置查询超时时间

如果无法通过会话变量全局设置 ob_query_timeout,也可以在每条 SQL 中通过 Hint 动态设置查询超时时间。例如:

SELECT /*+ QUERY_TIMEOUT(900000000) */ * FROM your_table WHERE condition;

注意:此方法需要在每条 SQL 中手动添加 Hint,可能不适合大规模使用。


总结

  1. 推荐方法:通过 Druid 的 connection-init-sql 配置项,在每次会话建立时自动设置 ob_query_timeout
  2. 灵活方法:使用 MyBatis 插件动态设置会话变量。
  3. 备用方法:在每条 SQL 中通过 Hint 设置查询超时时间。

以上方法均可以在不修改租户级别配置的情况下,实现每次会话的 ob_query_timeout 设置。如果仍有问题,请进一步检查连接池和驱动版本的兼容性。

详情请参考:

  1. enable_sql_plan_monitor
  2. 系统变量总览
  3. 列存 FAQ
  4. 诊断分析
  5. enable_sql_extension
  6. SQL FAQ

(小助手的答复已结束,如未能解决您的问题,请继续提问并等待其他同学的回复,谢谢!)

建议客户修改呗,一劳永逸了 :joy:

&sessionVariables=ob_query_timeout=xxxxxxx

1 个赞