在 YashanDB 使用过程中,有些用户反馈:在修改表字段长度后,业务应用通过 JDBC 接口访问数据库时,突然报出了如下异常:

YAS-04007 Message:result set metadata changed
image.png

如果不了解其成因,很容易误以为是数据库异常。但实际上,这个问题有特定的触发机制,理解后完全可以规避。

一、问题现象

当在 YashanDB 中对已有表执行 ALTER TABLE MODIFY 修改字段长度操作后,原本已经获取的 JDBC PreparedStatement 在继续执行时,会抛出 YAS-04007 异常,导致业务访问中断。

异常截图通常如下所示:

image.png
二、风险及影响

客户端业务访问数据库时出现异常,影响正常读写;

由于 PreparedStatement 失效,可能导致应用层批量操作失败;

如果大规模触发,会造成短时间业务不可用。

这个问题影响 所有版本的 YashanDB,不是个别版本缺陷。

三、根本原因解析

问题出现的核心原因在于:

客户端 JDBC 在预编译阶段,基于当前表结构缓存了 ResultSet Metadata;

后续如果数据库端修改了表结构(如字段长度变化),原有的 PreparedStatement 中的 metadata 信息与实际表结构不再一致;

继续使用老 PreparedStatement 发请求,数据库端检测到 schema 变更,因此抛出 YAS-04007 异常提示。

尤其是在现网环境中,很多中间件(如 Druid)默认开启了 pool-prepared-statements 参数,会缓存 PreparedStatement,从而更容易触发此类问题。

四、问题重现步骤示例

在 YashanDB 中创建表,例如:

create table test (
tname varchar2(32)
);

image.png
通过如下 Java 代码获取 PreparedStatement,并执行查询:

PreparedStatement pstmt = conn.prepareStatement("select * from test where tname = ?");

在程序执行期间,用其他工具(如 yasql)执行:

alter table test modify (tname varchar2(36));

程序继续使用原有 pstmt 执行查询或更新操作时,就会抛出 YAS-04007 异常。

五、规避方法

出现这种情况时,临时的处理方法是:

重启业务 Java 进程,使得新的连接重新拉取新的表结构元数据;

或者在数据库结构变更后,重建连接池,刷新已缓存的 PreparedStatement。

从设计层面来说,建议在应用端:

禁止在业务高峰期直接修改线上表结构;

如果必须修改,提前做好连接池重建或应用重启的规划;

对于 Druid 等中间件,评估是否关闭 pool-prepared-statements,或者在检测到 schema 变化时自动失效缓存。

六、研发分析与结论

经过研发团队分析,当前 YashanDB 的处理符合行业通用逻辑。遇到 schema 变化导致 metadata 不一致时,抛出 YAS-04007 是合理保护行为,避免出现数据错乱。因此,暂不考虑修改数据库侧的默认行为。

七、小结提醒

在使用 JDBC 连接 YashanDB 过程中,如果遇到 YAS-04007 错误,不要慌,优先排查是否存在表结构变更;

表结构调整要做好发布窗口管理,避免影响在线业务;

应用程序要具备一定的容错机制,遇到 metadata 变化时能自动刷新连接或提示需要重启。


数据库砖家
1 声望0 粉丝