问题现象
在数据库操作(如 JDBC、Python 的 SQLAlchemy、Node.js 的 Knex.js 等)中,useArrayBinding 通常指通过一次操作处理多个数据行,而不是逐条执行 SQL 语句。 在 OceanBase 数据库 V4.2.1 集群中,使用 Prepared Statement 语句,当没有绑定变量并且只有一条 SQL 语句的时候,然后执行 ps.addbatch 操作后,在执行 ps.executebatch 会卡住,执行过程会卡住,不返回任何错误信息。而在 OceanBase 数据库 V4.2.5 BP3 版本中,同样的操作会导致报错 -4007, Not supported feature or function。
-- 示例 SQL 语句,不带绑定变量
UPDATE table_name SET column1 = value1 where column2 = value2;
当把语句中的 value1 替换成 ? 作为参数占位符的时候,可以正常执行。
UPDATE table_name SET column1 = value1 where column2 = ?;
批量执行包含相同类型常量的 UNION 语句。
insert into t_r2 (select 1 from dual union select 2 from dual);
关键诊断信息
触发条件
使用
useArrayBinding=true的连接配置执行更新语句。审核通过 addBatch 执行的 SQL 语句是否都使用
?作为占位符。
事前巡检
检查应用程序中是否使用了
useArrayBinding=true的连接配置。审核 SQL 语句,确保所有参数都使用了
?作为占位符。
事后诊断
查看 OBServer 的日志文件,确认是否有异常记录或错误码未被正确处理的情况。
在未修复的版本,执行 hang 住。在修复的版本,会返回报错
ORA-00600: internal error code, arguments: -4007, oci arraybinding has no parameters not supported。[2025-05-23 17:04:23.138721] WDIAG [SERVER] process_execute_stmt (obmp_stmt_execute.cpp:1845) [36256][T1002_L0_G0][T1002][xxxxx-xxxxx-xxxxx-xxxxx-xxxxx] [lt=1][errcode=-4007] arraybinding has no parameters(ret=-4007, arraybinding_size_=0) [2025-05-23 17:04:23.138738] WDIAG process_execute_stmt (obmp_stmt_execute.cpp:1846) [36256][T1002_L0_G0][T1002][xxxxx-xxxxx-xxxxx-xxxxx-xxxxx] [lt=15][errcode=-4007] ORA-00600: internal error code, arguments: -4007, oci arraybinding has no parameters not supported [2025-05-23 17:04:23.138754] INFO [SERVER] send_error_packet (obmp_packet_sender.cpp:376) [36256][T1002_L0_G0][T1002][xxxxx-xxxxx-xxxxx-xxxxx-xxxxx] [lt=8] REACH SYSLOG RATE LIMIT [bandwidth] [2025-05-23 17:04:23.138776] WDIAG [SERVER] process (obmp_stmt_execute.cpp:2048) [36256][T1002_L0_G0][T1002][xxxxx-xxxxx-xxxxx-xxxxx-xxxxx] [lt=12][errcode=-4007] fail execute sql(sql_id="", stmt_id=1, ret=-4007) [2025-05-23 17:04:23.536790] INFO [RPC.OBMYSQL] destroy (obsm_conn_callback.cpp:243) [36981][sql_nio5][T0][Y0-0000000000000000-0-0] [lt=1] connection close(sessid=3221553071, proxy_sessid=0, tenant_id=1002, server_id=1, from_proxy=false, from_java_client=false, c/s protocol="OB_MYSQL_CS_TYPE", is_need_clear_sessid_=true, is_sess_alloc_=true, ret=0, trace_id=xxxxx-xxxxx-xxxxx-xxxxx-xxxxx, conn.pkt_rec_wrapper_=[start_pkt_pos_:0, cur_pkt_pos_:25, pkt_rec[0]:{send:obp_mysql_header_{len_:144, seq_:3}, pkt_name:"PKT_OKP", obp_mysql_header_.is_send_:1}, pkt_rec[1]:{send:obp_mysql_header_{len_:94, seq_:2}, pkt_name:"PKT_OKP", obp_mysql_header_.is_send_:1}, pkt_rec[2]:{send:obp_mysql_header_{len_:126, seq_:2}, pkt_name:"PKT_OKP", obp_mysql_header_.is_send_:1}, pkt_rec[3]:{receive:obp_mysql_header_{len_:166, rec_:166, seq_:0}, pkt_name:"COM_QUERY", obp_mysql_header_.type_:3, obp_mysql_header_.is_send_:0}, pkt_rec[4]:{send:obp_mysql_header_{len_:5, seq_:2}, pkt_name:"PKT_RESHEAD", obp_mysql_header_.is_send_:1}, pkt_rec[5]:{send:obp_mysql_header_{pkt_num_:6, seq_:8}, pkt_name:"PKT_FIELD", obp_mysql_header_.is_send_:1}, pkt_rec[6]:{send:obp_mysql_header_{len_:9, seq_:9}, pkt_name:"PKT_EOF", obp_mysql_header_.is_send_:1}, pkt_rec[7]:{send:obp_mysql_header_{pkt_num_:1, seq_:10}, pkt_name:"PKT_ROW", obp_mysql_header_.is_send_:1}, pkt_rec[8]:{send:obp_mysql_header_{len_:9, seq_:11}, pkt_name:"PKT_EOF", obp_mysql_header_.is_send_:1}, pkt_rec[9]:{receive:obp_mysql_header_{len_:81, rec_:81, seq_:0}, pkt_name:"COM_QUERY", obp_mysql_header_.type_:3, obp_mysql_header_.is_send_:0}, pkt_rec[10]:{send:obp_mysql_header_{len_:5, seq_:2}, pkt_name:"PKT_RESHEAD", obp_mysql_header_.is_send_:1}, pkt_rec[11]:{send:obp_mysql_header_{pkt_num_:4, seq_:6}, pkt_name:"PKT_FIELD", obp_mysql_header_.is_send_:1}, pkt_rec[12]:{send:obp_mysql_header_{len_:9, seq_:7}, pkt_name:"PKT_EOF", obp_mysql_header_.is_send_:1}, pkt_rec[13]:{send:obp_mysql_header_{pkt_num_:1, seq_:8}, pkt_name:"PKT_ROW", obp_mysql_header_.is_send_:1}, pkt_rec[14]:{send:obp_mysql_header_{len_:9, seq_:9}, pkt_name:"PKT_EOF", obp_mysql_header_.is_send_:1}, pkt_rec[15]:{receive:obp_mysql_header_{len_:78, rec_:78, seq_:0}, pkt_name:"COM_QUERY", obp_mysql_header_.type_:3, obp_mysql_header_.is_send_:0}, pkt_rec[16]:{send:obp_mysql_header_{len_:5, seq_:2}, pkt_name:"PKT_RESHEAD", obp_mysql_header_.is_send_:1}, pkt_rec[17]:{send:obp_mysql_header_{pkt_num_:3, seq_:5}, pkt_name:"PKT_FIELD", obp_mysql_header_.is_send_:1}, pkt_rec[18]:{send:obp_mysql_header_{len_:9, seq_:6}, pkt_name:"PKT_EOF", obp_mysql_header_.is_send_:1}, pkt_rec[19]:{send:obp_mysql_header_{pkt_num_:1, seq_:7}, pkt_name:"PKT_ROW", obp_mysql_header_.is_send_:1}, pkt_rec[20]:{send:obp_mysql_header_{len_:9, seq_:8}, pkt_name:"PKT_EOF", obp_mysql_header_.is_send_:1}, pkt_rec[21]:{receive:obp_mysql_header_{len_:19, rec_:19, seq_:0}, pkt_name:"COM_QUERY", obp_mysql_header_.type_:3, obp_mysql_header_.is_send_:0}, pkt_rec[22]:{send:obp_mysql_header_{len_:32, seq_:2}, pkt_name:"PKT_OKP", obp_mysql_header_.is_send_:1}, pkt_rec[23]:{receive:obp_mysql_header_{len_:64, rec_:64, seq_:0}, pkt_name:"COM_STMT_PREXECUTE", obp_mysql_header_.type_:161, obp_mysql_header_.is_send_:0}, pkt_rec[24]:{send:obp_mysql_header_{len_:96, seq_:2}, pkt_name:"PKT_ERR", obp_mysql_header_.is_send_:1}], disconnect_state=4)检查客户端执行日志,确认是否出现了执行挂起的现象。
问题原因
当 arraybinding 设置了 save_exception 标志为 true 时,理论上可以保存错误码并向客户端发送 OK 包。然而,在某些分支中,这一标志未被正确检查,导致即使遇到错误也不向客户端发送任何响应,从而使得客户端陷入挂起状态。这是由于 OceanBase 内核的一个 BUG 引起的功能性问题。
问题的风险及影响
SQL 执行过程中客户端可能长时间无响应,导致业务中断。
应用程序可能因为长时间等待而超时或崩溃。
影响租户
影响 OceanBase 数据库中的 Oracle 租户,对于 SYS 租户和 MySQL 租户无影响。
影响版本
OceanBase 数据库企业版 V4.2.1 GA(oceanbase-4.2.1.0-100000182023092722)及之后版本、V4.2.5 GA(oceanbase-4.2.5.0-100000082024102022)及之后版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V4.2.1 BP11 Hotfix4(oceanbase-4.2.1.11-111040032025061010)版本、V4.2.1 BP11 Hotfix5(oceanbase-4.2.1.11-111050022025071110)版本、V4.2.1 BP11 Hotfix6(oceanbase-4.2.1.11-111060012025071816)版本、V4.2.1 BP11 Hotfix7(oceanbase-4.2.1.11-111070032025081120)版本、V4.2.1 BP11 Hotfix8(oceanbase-4.2.1.11-111080012025082014)版本、V4.2.1 BP11 Hotfix9(oceanbase-4.2.1.11-111090012025091215)版本、V4.2.1 BP11 Hotfix10(oceanbase-4.2.1.11-111100012025092309)版本、V4.2.1 BP11 Hotfix11(oceanbase-4.2.1.11-111110012025101314)版本、V4.2.1 BP11 Hotfix12(oceanbase-4.2.1.11-111120022025110311)版本、V4.2.1 BP11 Hotfix13(oceanbase-4.2.1.11-111130012025120810)版本、V4.2.1 BP11 Hotfix14(oceanbase-4.2.1.11-111140012026010621)版本、V4.2.1 BP11 Hotfix15(oceanbase-4.2.1.11-111150022026020915)版本、V4.2.1 BP11 Hotfix16(oceanbase-4.2.1.11-111160012026032518)版本、V4.2.5 BP2(oceanbase-4.2.5.2-102000122025011711)及之后版本。
作为临时措施,避免在 SQL 语句中直接使用具体值,改为使用绑定变量。
规避方式
在应用程序中禁用
useArrayBinding配置项,或确保所有 SQL 语句均使用绑定变量。对于必须批量执行的 SQL 语句,考虑重构 SQL 逻辑以避免触发此问题。