美文网首页MySQL程序员
MySQL5.7 union all + jdbc预编译参数us

MySQL5.7 union all + jdbc预编译参数us

作者: 偏执的工匠 | 来源:发表于2018-10-25 16:22 被阅读2次

1. 问题背景

生产环境Percona MySQL 5.7.19 执行SQL报错 如下:

java.sql.SQLException: Unknown type '14 in column 0 of 1 in binary-encoded result set.
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861)
        at com.mysql.jdbc.MysqlIO.extractNativeEncodedColumn(MysqlIO.java:4558)
        at com.mysql.jdbc.MysqlIO.unpackBinaryResultSetRow(MysqlIO.java:4472)
        at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:2045)
        at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:3400)
        at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:470)
        at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:3112)
        at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:2341)
        at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1368)
        at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:783)
        at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1966)
        at JDBCClient.main(JDBCClient.java:39)

2. 排查问题

通过网络搜索报错信息,找到MySQL的一个Bug信息,见链接:https://bugs.mysql.com/bug.php?id=87534

该Bug复现条件:

  1. 应用程序使用jdbc连接MySQL数据库,并且打开jdbc预编译参数useServerPrepStmts=true
  2. 应用程序中执行了含有UNION ALL的SQL,并且SQL执行返回的数据中包含有DATE类型的字段。

搜索MySQL 5.7.19 之后版本的Release Note,发现在5.7.22 版本对这一问题进行了修复,见链接:
https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-22.html

Metadata from result sets for UNION ALL queries could say NEWDATE rather than DATE. (Bug #27422376)

经过测试,5.7.21 能够复现该Bug,5.7.22 没有复现,确认该Bug 在 5.7.22中已解决。

3. 源码分析

通过在MySQL 源码的git log中搜索内部Bug号#27422376,对比代码差异,定位到 union all 在遇到DATE类型字段时,返回的是内部使用的NEWDATE类型,导致jdbc接收到这种NEWDATE类型无法识别,报错。官方在修复这个问题时,通过real_type_to_type 这个函数,将 MYSQL_TYPE_NEWDATE 转换为 MYSQL_TYPE_DATE。


image.png image.png

查看 MYSQL_TYPE_NEWDATE 的定义:


image.png

MYSQL_TYPE_NEWDATE 枚举类型,值为14, MYSQL_TYPE_DATE 值为10,jdbc 在收到 MYSQL_TYPE_NEWDATE (14) 无法识别该字段类型,所以报错。

ava.sql.SQLException: Unknown type '14 in column 0 of 1 in binary-encoded result set.

通过查看mysql connector-J 5.1.45 源码 MysqlIO.java 4558行代码,我们看到jdbc源码中有个switch语句,只能识别MysqlDefs.FIELD_TYPE_DATE, 虽然MysqlDefs.FIELD_TYPE_NEWDATE 有定义,但是在switch 语句中并没有 case MysqlDefs.FIELD_TYPE_NEWDATE, 导致NEWDATE在这里无法被识别,走到default的代码逻辑。经过社区的讨论,认为这个Bug,不应该由jdbc修复,应当在MySQL Server中修复, 毕竟NEWDATE只是内部使用的一个数据类型。

image.png image.png

4. 规避方案

  1. 升级MySQL到5.7.22 及以上版本
  2. 关闭jdbc预编译参数useServerPrepStmts=false,可能有性能损耗
  3. 修改sql,在外面包装一层select,如 select * from <your sql>
  4. 修改表结构,不使用DATE类型字段

相关文章

  • MySQL5.7 union all + jdbc预编译参数us

    1. 问题背景 生产环境Percona MySQL 5.7.19 执行SQL报错 如下: 2. 排查问题 通过网络...

  • SQL union和union all操作符

    一、union和union all区别 union会去重,union all不会去重 二、SQL union操作符...

  • SQL [UNION]和[UNION ALL]用法

    原文链接:SQL UNION和UNION ALL用法 一、概述 union和union all都用于合并多个查询,...

  • union与union all

    union和union all的区别是,union会自动压缩多个结果集合中的重复结果,而union all则将所有...

  • union比union all区别

    union去重并排序,union all直接返回合并的结果,不去重也不排序;union all比union性能好;

  • SQL面试题,快问快答!

    1. UNION ALL 与 UNION 的区别 UNION和UNION ALL关键字都是将两个结果集合并为一个。...

  • 杂项

    1.UNION与UNION ALL合并UNION将返回两个查询的结果并去除其中的重复部分,UNION ALL与UN...

  • 数据库查询

    一、union和union_all 1.union 和 union_all 将两个结果集合并在一起(可以查询不同的...

  • 数据库批量添加

    UNION ALL SQLBulkCopy

  • 8.15

    1.union连接表的时候去了重复的内容,保留表的重复的值需要用union all。union all 保留重复,...

网友评论

    本文标题:MySQL5.7 union all + jdbc预编译参数us

    本文链接:https://www.haomeiwen.com/subject/jcaqtqtx.html