⭐优雅解决数据库类型跟Java对象属性类型不对应!

什么是数据库类型跟Java对象属性类型不对应

举例说一下: 数据库表中有一个名为 "age" 的列,其类型为 VARCHAR,存储了年龄信息,但在 Java 对象的类定义中,本应该对应的属性类型是String或者object,但是实际对应属性的类型是 Integer,就会出现类型转换错误的问题。

关于数据库类型跟Java对象属性类型不对应的解决办法: 通过设置一个处理类继承BaseTypeHandler这个类,然后配置相对应的转换方法。

其中,BaseTypeHandler实现了TypeHandler(字段类型处理器)接口,

什么是TypeHandler接口呢?

TypeHandler

TypeHandler就是应用程序和数据库之间的拦截器,所有的操作,都会先通过TypeHandler处理。

作用:处理 Java 对象和数据库类型之间的转换,通过实现这个接口来完成自定义类型处理器

BaseTypeHandler

BaseTypeHandler定义了一些默认的转换逻辑,属于类型转换类型实现需要的基础东西。比如:

arduino 复制代码
setParameter :将 Java 对象转换为数据库参数。

getResult :从数据库结果集中提取并转换数据为 Java 对象。

通过继承 BaseTypeHandler,通过继承 BaseTypeHandler,你只需关注具体类型的转换逻辑,无需实现所有的方法,可以更便捷地实现自定义的类型处理器。

举例了解一下

先定义一个拓展BaseTypeHandler的处理器,担当的角色是抽象的数组类型处理器, 负责数组对象到 JSON 字符串的转换。

ArrayObjectJsonTypeHandler

typescript 复制代码
@Slf4j
//@MappedJdbcTypes 是 MyBatis 中的注解,指定了该类型处理器与数据库的关联。
@MappedJdbcTypes(value = {JdbcType.OTHER}, includeNullJdbcType = true)
//用于处理数组对象的类型。
public class ArrayObjectJsonTypeHandler<E> extends BaseTypeHandler<E[]> {
    //创建一个 Jackson 的 ObjectMapper 对象,用于进行对象与 JSON 字符串的序列化和反序列化
    private static final ObjectMapper MAPPER = new ObjectMapper();
    // 定义一个字符串常量,表示空数组的 JSON 字符串
    private static final String STRING_JSON_ARRAY_EMPTY = "[]";

    //类加载时执行
    static {
        // 未知字段忽略
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 不使用科学计数
        MAPPER.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        // null 值不输出(节省内存)
        MAPPER.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);
    }
//数组的类型
    private final Class<E[]> type;

    //类的构造函数,接收一个数组的类型参数,并将其赋值给 type 变量
    public ArrayObjectJsonTypeHandler(Class<E[]> type) {
        Objects.requireNonNull(type);
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E[] parameter, JdbcType jdbcType) throws SQLException {
       //转为JSON字符串
        ps.setString(i, toJson(parameter));
    }

    @Override
    public E[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
        //JSON字符串转对应Java类型,然后返回(取结果的过程)
        return toObject(rs.getString(columnName), type);
    }

    @Override
    public E[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return toObject(rs.getString(columnIndex), type);
    }

    @Override
    public E[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return toObject(cs.getString(columnIndex), type);
    }

    /**
     * object 转 json
     *
     * @param obj 对象
     * @return String json字符串
     */
    private String toJson(E[] obj) {
        if (ArrayUtils.isEmpty(obj)) {
            return STRING_JSON_ARRAY_EMPTY;
        }

        try {
            //将给定的 Java 对象 obj 序列化为对应的 JSON 字符串。
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("mybatis column to json error,obj:" + Arrays.toString(obj), e);
        }
    }

    /**
     * 转换对象
     *
     * @param json  json数据
     * @param clazz 类
     * @return E
     */
    private E[] toObject(String json, Class<E[]> clazz) {
        if (json == null) {
            return null;
        }

        if (!StringUtils.hasText(json)) {
            return newArray(clazz);
        }

        try {
            //将给定的 JSON 字符串 json 反序列化为指定类型 clazz 的对象
            return MAPPER.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            log.error("mybatis column json to object error,json:{}", json, e);
            return newArray(clazz);
        }
    }

    //@SuppressWarnings("unchecked") 注解用于压制类型转换警告
    //就是告诉编译器我这些类型转换是安全的,可以忽略调用 Array.newInstance 方法时的类型转换警告。
    @SuppressWarnings("unchecked")
    private E[] newArray(Class<E[]> clazz) {
        return (E[]) Array.newInstance(clazz.getComponentType(), 0);
    }
}

主要作用是数组类型转换json

大致解释下:首先定义了Jackson的ObjectMapper对象,用来进行对象与JSON字符串的序列化和反序列化

静态代码块进行了一些mapper的配置。

然后写了toObject和toJSON这两个方法(为当前类的自定义方法,不是重写方法),是JSON字符 串和数组类型的相互转换。

之后在重写方法里面进行使用,其中:

setNonNullParameter的作用是将 Java 对象类型的值转换为数据库可接受的类型,以便进行数据存储。

getNullableResult 的作用是将从数据库中获取的特定类型的值转换为 Java 对象类型。

@MappedJdbcTypes 注解在 ArrayObjectJsonTypeHandler 类上的作用是取未知或不常见的数据库类型数据时,会使用这个处理器。

这样,一个数组类型转json的类型处理器就弄好了,这时如果我们想把Integer数组转json,就很简单了

看下面代码:

IntegerArrayJsonTypeHandler

less 复制代码
@Slf4j
@Component
@MappedTypes(value = {Integer[].class})
@MappedJdbcTypes(value = {JdbcType.VARCHAR}, includeNullJdbcType = true)
public class IntegerArrayJsonTypeHandler extends ArrayObjectJsonTypeHandler<Integer> {
    public IntegerArrayJsonTypeHandler() {
        super(Integer[].class);
    }
}

主要看这两个注解:@MappedJdbcTypes(value = {JdbcType.VARCHAR}, includeNullJdbcType = true)指定数据库类型和varchar类型的映射关系。就是说Mybatis根据注解指定的varchar类型,当从数据库中获取这种类型的值,会使用这个处理器进行转换。

@MappedTypes(value = {Integer[].class}) 指定Integeter[] 类型对象和相应的数据库类型之间的映射关系。就是说把这个Integer[]类型对象存入数据库时,会使用这个处理器进行转换。

总结

自定义类型转换器继承BaseTypeHandler解决类型转换问题,其中

  • setNonNullParameter是进行转换为对应数据库类型
  • getNonNullParameter是取数据库数值时转换为Java对象类型
  • @mapperType是用于setNonNullParameter
  • @mapperJDBCType用于getNonNullParameter
相关推荐
徐*红13 分钟前
java 线程池
java·开发语言
尚学教辅学习资料13 分钟前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
2401_8576363913 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
1 9 J15 分钟前
Java 上机实践4(类与对象)
java·开发语言·算法
Code apprenticeship16 分钟前
Java面试题(2)
java·开发语言
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
憨子周1 小时前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨3 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404193 小时前
javaSE面试题
java·开发语言·面试
Fiercezm3 小时前
JUC学习
java