6

mybatis查询mysql 数据库中 BLOB字段,结果出现乱码 - 天下没有收费的bug

 1 year ago
source link: https://www.cnblogs.com/LoveBB/p/16406345.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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'

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

image-20220623180920568
image-20220623180943762

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

1、url 属性排查

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

    @Value("${spring.datasource.druid.url}")
    String dateURL;

    log.info("数据库连接配置 url 属性为: "+dateURL);

结果如下:

image-20220623181436544


2、IDEA 编码排查

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

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

image-20220623181629922

3、mybatis xml文件排查

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

image-20220623181851200

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

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

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


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

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

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

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

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

    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 类的地址

image-20220623183403389

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK