场景:
开发中遇到这样一种情况,页面传来一个字符串,数据长度非常大,远远大出了varchar2类型的默认长度4000,这里就用到了oracle的blob字段;(其实这里使用clob字段更好,因为clob是大字符字段而blob是大的字节字段两者都用来存储大的数据,但是使用场景不同)
问题:
我们知道页面传递的字符串类型String,但是blob类型只能接受的byte[]类型,那么mybatis如何实现这两者的转换呢?

1 解决思路

最容易想到在接收之后将字符串转成字节数组 如: string.getBytes();
但是你想过没有如果我们使用的是pojo实体接收的前端数据,那么前端传递过来的其实就只是字符串类型,所以我们pojo定义的属性类型也只能为String(数字类型参数除外,可自动转换情况为特例);此时如果以pojo实体的方式直接入参向数据库插入数据,很明显会报错: 类型不匹配.

完美解决方案:
使用Mybatis的TypeHandler类解决
该handler其实就是mybatis调用写入或者读取方法之前,完成参数的处理
我们通过实现其接口或者继承其子类的形式完成对blob字段的处理更好

2 场景再现

先来看一下pojo字段和数据库字段类型不匹配的报错:

blob 如何读取 mysql blob 图片 mybatis读取blob字段为输入流_java

上图中testBlobDesc就是对应的数据库的blob字段,可以看到属性字段类型为String

blob 如何读取 mysql blob 图片 mybatis读取blob字段为输入流_java_02

运行报错截图如下:

blob 如何读取 mysql blob 图片 mybatis读取blob字段为输入流_字段_03

3 解决

我们实现的方式有很多可以实现TypeHandler接口或者继承BaseTypeHandler父类我这里使用的继承

package show.mrkay.handler;

import org.apache.ibatis.type.*;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.*;

/**
 * @Description: 自定义Blob字段类型处理器
 * @ProjectName: SpringBootProjects
 * @ClassName: CustomColbTypeHandler
 * @Author: MrKay
 * @Date: 2021/5/16
 */
 //对应要处理数据库字段
@MappedJdbcTypes(JdbcType.BLOB)
//pojo中对应的属性类型
@MappedTypes(String.class)
public class CustomColbTypeHandler extends BaseTypeHandler {
    /**
     * 插入数据时调用此方法
     *
     * @param ps        预处理器
     * @param i
     * @param parameter
     * @param jdbcType
     * @MethodName: setNonNullParameter
     * @return: void
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
// 声明一个输入流对象
        ByteArrayInputStream bis = null;
        String param = null;
        if (parameter != null) {
        //这里强转是因为知道了是String类型,可以看具体情况而定
            param = (String) parameter;
        }
        try {
            // 把字符串转为字节流
            bis = new ByteArrayInputStream(param.getBytes("utf-8"));
        } catch (Exception e) {
            throw new RuntimeException("Blob Encoding Error!");
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    throw new RuntimeException("Blob Encoding Error!");
                }
            }
        }
        ps.setBinaryStream(i, bis, param.length());
    }

    /**
     * 读取数据时候调用此方法
     *
     * @param rs
     * @param columnName
     * @MethodName: getNullableResult
     * @return: java.lang.Object
     */
    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Blob 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, "utf-8");
        } catch (Exception e) {
            throw new RuntimeException("Blob Encoding Error!");
        }
    }

    /**
     * 读取方法同上,方法重载
     *
     * @param rs
     * @param columnIndex
     * @MethodName: getNullableResult
     * @return: java.lang.Object
     */
    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    /**
     * 读取方法同上,方法重载
     *
     * @param cs
     * @param columnIndex
     * @MethodName: getNullableResult
     * @return: java.lang.Object
     */
    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
}

增加如下mybatis配置

mybatis:
  #  该配置项配置了MyBatis配置文件保存路径
  mapper-locations: classpath*:show/mrkay/mapper/*.xml
  type-handlers-package: show.mrkay.handler

再次测试

blob 如何读取 mysql blob 图片 mybatis读取blob字段为输入流_字段_04


blob 如何读取 mysql blob 图片 mybatis读取blob字段为输入流_字段_05