如何解决mybatis查询MySQL BLOB字段乱码问题?

2026-04-18 03:201阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1526个文字,预计阅读时间需要7分钟。

如何解决mybatis查询MySQL BLOB字段乱码问题?

起因

mybatis-plus 通过Mapper 查询数据,映射出来的BLOB字段中的yml数据中文是乱码的

--- DefaultValue: '' Formula: '' HintContent: '' HintType: '' OptionsColor: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' OptionsIcon: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleComments: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleValues: 处理: 处理 外修中: 外修中 完成: 完成 接单: 接单 新建: 新建 评价: 评价 转信息科: 转信息科 转总务科: 转总务科 转设备科: 转设备科 Regex: '' RegexHint: '' TreeView: '0' Unique: '0'

我们看一下正常的数据是长下面这样的

--- DefaultValue: '' Formula: '' HintContent: '' HintType: '' OptionsColor: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' OptionsIcon: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleComments: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleValues: 处理: 处理 外修中: 外修中 完成: 完成 接单: 接单 新建: 新建 评价: 评价 转信息科: 转信息科 转总务科: 转总务科 转设备科: 转设备科 Regex: '' RegexHint: '' TreeView: '0' Unique: '0'

在来看看这个字段在数据库中存储的样子:

排查过程

一开始想到的就是经典的乱码问题。所以尝试了如下方法

1、url 属性排查

检查数据库 url 链接上有没有添加 characterEncoding=UTF-8,这里查看是没有问题的,因为用的是nacos,担心是覆盖出了问题。我还特意在代码中打印出来了。

@Value("${spring.datasource.druid.url}") String dateURL; log.info("数据库连接配置 url 属性为: "+dateURL);

结果如下:


2、IDEA 编码排查

排查是否是 IDEA 问题,虽然概率小,但是也要排查一下,排查结果还是没有问题

排查路径:Setting--->Editor--->File Encodings

3、mybatis xml文件排查

这里主要是看 xml 有时候是手写或者网上复制过来的话,也可能会造成乱码。排查结果也是没有问题


4、排查数据库中的数据是否乱码

这个时候,我们在查询步骤中基本上都排查完了,现在怀疑是不是插入时,数据库本身存储就是乱码的

直接去数据库中查找改字段,并把数据放到 Notepad++ 或者其他编辑器里面,可以确定数据库中存的数据是正常的


5、排查查询其他中文字段是否会出现乱码

直接写SQL去查询其他中文字段,查出来的结果是正常的,这就证明了问题确实是出现在 BLOB 这个字段里面了

解决办法

到这里,基本上排查的方法都用上了,其实上面的排查过程还是比较消耗时间的,这里我就不做过多繁琐的描述了,还有一些其他的排查方式。比如换机器,换配置文件的等也都一一试过,但是环境这方面的排查,我就不讲述了,实在是无聊又耗时间。最后确定问题出现在BLOB类型之后,参考网上的文章做了如下的解决方案。

把查出来的数据,作为字节数组,保留最完整的原始性,在把 byte[] 强转为 UTF-8 的 String 类型。

此时就去String中尝试查找是否纯在此类。万幸的是找到了

如何解决mybatis查询MySQL BLOB字段乱码问题?

public String(byte bytes[], String charsetName) throws UnsupportedEncodingException { this(bytes, 0, bytes.length, charsetName); }

最后是使用这个方法实现了转换

new String( dynamicFieldConfig字段值 , "utf-8" );

但是我们项目中,很多地方都用到了这个字段。


此时想到mybatis的结果集拦截器,我们可以在结果集拦截器中对这个字段进行拦截,并对他做语言转换处理。

最后实现的效果:

package com.dt.cloud.tools; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.io.ByteArrayInputStream; import java.io.UnsupportedEncodingException; import java.sql.*; /** * @Description: * @author: zch * @Date: 2022/6/23 16:36 * @Version 1.0 */ public class ConvertBlobTypeHandler extends BaseTypeHandler<String> { private static final String DEFAULT_CHARSET = "utf-8"; @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ByteArrayInputStream bis; try { bis = new ByteArrayInputStream(parameter.getBytes(DEFAULT_CHARSET)); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Blob Encoding Error!"); } ps.setBinaryStream(i, bis, parameter.length()); } @Override //rs 为返回结果集,columnName 就是我们需要处理的字段名,当我们根据字段名在返回结果集中找出的这个字段就是 longblob 类型的数据了 public String getNullableResult(ResultSet rs, String columnName) throws SQLException { Blob blob = rs.getBlob(columnName); byte[] returnValue = null; if (null != blob) { returnValue = blob.getBytes(1, (int) blob.length()); } try { // 核心代码,把结果集拦截下来,并且强制转换为utf-8格式 return new String(returnValue, DEFAULT_CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Blob Encoding Error!"); } } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { Blob blob = cs.getBlob(columnIndex); byte[] returnValue = null; if (null != blob) { returnValue = blob.getBytes(1, (int) blob.length()); } try { return new String(returnValue, DEFAULT_CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Blob Encoding Error!"); } } @Override public String getNullableResult(ResultSet arg0, int arg1) throws SQLException { return null; } }

在我们的 mapper 文档中需要拦截的 resultMap 中的字段中增加一个 typeHandler 类型拦截器,这个 typeHandler 的值就是我们 ConvertBlobTypeHandler 类的地址

最后总结:数据库中的存储使用的就是 longblob 类型,这个类型在查询出来的时候如果不进行处理的话就会出现乱码问题。简单的处理方式就是在 Mybatis 查询数据库的时候增加一个拦截器,给这个类型的字段改变一下编码方式。

本文共计1526个文字,预计阅读时间需要7分钟。

如何解决mybatis查询MySQL BLOB字段乱码问题?

起因

mybatis-plus 通过Mapper 查询数据,映射出来的BLOB字段中的yml数据中文是乱码的

--- DefaultValue: '' Formula: '' HintContent: '' HintType: '' OptionsColor: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' OptionsIcon: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleComments: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleValues: 处理: 处理 外修中: 外修中 完成: 完成 接单: 接单 新建: 新建 评价: 评价 转信息科: 转信息科 转总务科: 转总务科 转设备科: 转设备科 Regex: '' RegexHint: '' TreeView: '0' Unique: '0'

我们看一下正常的数据是长下面这样的

--- DefaultValue: '' Formula: '' HintContent: '' HintType: '' OptionsColor: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' OptionsIcon: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleComments: 处理: '' 外修中: '' 完成: '' 接单: '' 新建: '' 评价: '' 转信息科: '' 转总务科: '' 转设备科: '' PossibleValues: 处理: 处理 外修中: 外修中 完成: 完成 接单: 接单 新建: 新建 评价: 评价 转信息科: 转信息科 转总务科: 转总务科 转设备科: 转设备科 Regex: '' RegexHint: '' TreeView: '0' Unique: '0'

在来看看这个字段在数据库中存储的样子:

排查过程

一开始想到的就是经典的乱码问题。所以尝试了如下方法

1、url 属性排查

检查数据库 url 链接上有没有添加 characterEncoding=UTF-8,这里查看是没有问题的,因为用的是nacos,担心是覆盖出了问题。我还特意在代码中打印出来了。

@Value("${spring.datasource.druid.url}") String dateURL; log.info("数据库连接配置 url 属性为: "+dateURL);

结果如下:


2、IDEA 编码排查

排查是否是 IDEA 问题,虽然概率小,但是也要排查一下,排查结果还是没有问题

排查路径:Setting--->Editor--->File Encodings

3、mybatis xml文件排查

这里主要是看 xml 有时候是手写或者网上复制过来的话,也可能会造成乱码。排查结果也是没有问题


4、排查数据库中的数据是否乱码

这个时候,我们在查询步骤中基本上都排查完了,现在怀疑是不是插入时,数据库本身存储就是乱码的

直接去数据库中查找改字段,并把数据放到 Notepad++ 或者其他编辑器里面,可以确定数据库中存的数据是正常的


5、排查查询其他中文字段是否会出现乱码

直接写SQL去查询其他中文字段,查出来的结果是正常的,这就证明了问题确实是出现在 BLOB 这个字段里面了

解决办法

到这里,基本上排查的方法都用上了,其实上面的排查过程还是比较消耗时间的,这里我就不做过多繁琐的描述了,还有一些其他的排查方式。比如换机器,换配置文件的等也都一一试过,但是环境这方面的排查,我就不讲述了,实在是无聊又耗时间。最后确定问题出现在BLOB类型之后,参考网上的文章做了如下的解决方案。

把查出来的数据,作为字节数组,保留最完整的原始性,在把 byte[] 强转为 UTF-8 的 String 类型。

此时就去String中尝试查找是否纯在此类。万幸的是找到了

如何解决mybatis查询MySQL BLOB字段乱码问题?

public String(byte bytes[], String charsetName) throws UnsupportedEncodingException { this(bytes, 0, bytes.length, charsetName); }

最后是使用这个方法实现了转换

new String( dynamicFieldConfig字段值 , "utf-8" );

但是我们项目中,很多地方都用到了这个字段。


此时想到mybatis的结果集拦截器,我们可以在结果集拦截器中对这个字段进行拦截,并对他做语言转换处理。

最后实现的效果:

package com.dt.cloud.tools; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.io.ByteArrayInputStream; import java.io.UnsupportedEncodingException; import java.sql.*; /** * @Description: * @author: zch * @Date: 2022/6/23 16:36 * @Version 1.0 */ public class ConvertBlobTypeHandler extends BaseTypeHandler<String> { private static final String DEFAULT_CHARSET = "utf-8"; @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ByteArrayInputStream bis; try { bis = new ByteArrayInputStream(parameter.getBytes(DEFAULT_CHARSET)); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Blob Encoding Error!"); } ps.setBinaryStream(i, bis, parameter.length()); } @Override //rs 为返回结果集,columnName 就是我们需要处理的字段名,当我们根据字段名在返回结果集中找出的这个字段就是 longblob 类型的数据了 public String getNullableResult(ResultSet rs, String columnName) throws SQLException { Blob blob = rs.getBlob(columnName); byte[] returnValue = null; if (null != blob) { returnValue = blob.getBytes(1, (int) blob.length()); } try { // 核心代码,把结果集拦截下来,并且强制转换为utf-8格式 return new String(returnValue, DEFAULT_CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Blob Encoding Error!"); } } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { Blob blob = cs.getBlob(columnIndex); byte[] returnValue = null; if (null != blob) { returnValue = blob.getBytes(1, (int) blob.length()); } try { return new String(returnValue, DEFAULT_CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Blob Encoding Error!"); } } @Override public String getNullableResult(ResultSet arg0, int arg1) throws SQLException { return null; } }

在我们的 mapper 文档中需要拦截的 resultMap 中的字段中增加一个 typeHandler 类型拦截器,这个 typeHandler 的值就是我们 ConvertBlobTypeHandler 类的地址

最后总结:数据库中的存储使用的就是 longblob 类型,这个类型在查询出来的时候如果不进行处理的话就会出现乱码问题。简单的处理方式就是在 Mybatis 查询数据库的时候增加一个拦截器,给这个类型的字段改变一下编码方式。