• 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 查询数据库的时候增加一个拦截器,给这个类型的字段改变一下编码方式。

  • 相关阅读:
    Unity 点击UI(按钮)与点击屏幕冲突
    UE5数字孪生制作(一) - QGIS 学习笔记
    使用jdbc技术,在数据库中存储大数据对象(使用字节IO流读取图片等给blob等二进制类型数据赋值)
    使用Java解压和压缩文件
    Java学习 --- 面向对象三大特征之封装
    代码随想录第五十七天
    spark导入elasticsearch
    Qt5开发从入门到精通——第五篇二节( 文本编辑器 Easy Word 开发 V1.1 详解 )
    词向量模型Word2Vec
    计算机视觉学习记录(七):图像分类
  • 原文地址:https://www.cnblogs.com/LoveBB/p/16406345.html