类型引起的索引失效-mybatis TypeHandler 完美解决

TypeHandler 是 MyBatis 中用于处理 Java 类型和 JDBC 类型之间转换的组件。通过自定义 TypeHandler,可以实现复杂的类型映射逻辑,例如将 Java 中的 long 类型与数据库中的 VARCHAR 类型进行转换。以下是 TypeHandler 的详细使用方法:


1. TypeHandler 的作用

  • 类型转换:将 Java 类型与 JDBC 类型进行双向转换。
  • 自定义逻辑 :实现复杂的类型映射逻辑,例如将 long 转换为 String,或将 JSON 字符串映射为 Java 对象。
  • 增强灵活性:解决 MyBatis 默认类型处理器无法处理的特殊场景。

2. 自定义 TypeHandler 的实现步骤

步骤 1:创建自定义 TypeHandler

自定义 TypeHandler 需要继承 BaseTypeHandler 或实现 TypeHandler 接口,并重写以下方法:

  • setNonNullParameter:将 Java 类型转换为 JDBC 类型。
  • getNullableResult:将 JDBC 类型转换为 Java 类型(有多个重载方法)。

示例:实现 LongString 的转换

java 复制代码
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class LongToStringTypeHandler extends BaseTypeHandler<Long> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {
        // 将 Long 类型转换为 String 类型,并设置到 PreparedStatement 中
        ps.setString(i, parameter.toString());
    }

    @Override
    public Long getNullableResult(ResultSet rs, String columnName) throws SQLException {
        // 从 ResultSet 中获取 String 类型的值,并转换为 Long 类型
        String value = rs.getString(columnName);
        return value == null ? null : Long.parseLong(value);
    }

    @Override
    public Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        // 从 ResultSet 中获取 String 类型的值,并转换为 Long 类型
        String value = rs.getString(columnIndex);
        return value == null ? null : Long.parseLong(value);
    }

    @Override
    public Long getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        // 从 CallableStatement 中获取 String 类型的值,并转换为 Long 类型
        String value = cs.getString(columnIndex);
        return value == null ? null : Long.parseLong(value);
    }
}

步骤 2:在实体类中指定 TypeHandler

在实体类的字段上使用 @TableField 注解(MyBatis-Plus)或 @TypeHandler 注解(MyBatis),指定自定义的 TypeHandler

示例:在 MyBatis-Plus 中使用

java 复制代码
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import org.apache.ibatis.type.JdbcType;

@TableName("your_table")
public class YourEntity {
    @TableField(value = "your_column", jdbcType = JdbcType.VARCHAR, typeHandler = LongToStringTypeHandler.class)
    private Long yourColumn; // 使用 long 类型
    // Getter 和 Setter 方法
}

步骤 3:在 MyBatis 配置中注册 TypeHandler

如果使用的是 MyBatis(非 MyBatis-Plus),需要在 MyBatis 配置文件中注册自定义 TypeHandler

示例:在 mybatis-config.xml 中注册

xml 复制代码
<typeHandlers>
    <typeHandler handler="com.example.LongToStringTypeHandler"/>
</typeHandlers>

检查下项目配置application.properties

是否包含自己定义的转换器路径

yaml 复制代码
mybatis-plus.type-handlers-package=自己的包路径
如下: mybatis-plus.type-handlers-package=com.xxx.type.handler

3. TypeHandler 的使用场景

场景 1:基本类型与字符串的转换

  • 例如:将 long 类型与 VARCHAR 类型相互转换。

场景 2:复杂对象的序列化与反序列化

  • 例如:将 Java 对象序列化为 JSON 字符串存储到数据库,或从数据库读取 JSON 字符串并反序列化为 Java 对象。

示例:JSON 与 Java 对象的转换

java

复制

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private final Class<T> type;

    public JsonTypeHandler(Class<T> type) {
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, objectMapper.writeValueAsString(parameter));
    }

    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return value == null ? null : objectMapper.readValue(value, type);
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        return value == null ? null : objectMapper.readValue(value, type);
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return value == null ? null : objectMapper.readValue(value, type);
    }
}

4. 注意事项

  • 类型匹配 :确保 TypeHandler 处理的 Java 类型与数据库字段类型匹配。
  • 性能影响:复杂的类型转换可能会影响性能,尽量避免在频繁查询的场景中使用。
  • 线程安全 :确保 TypeHandler 的实现是线程安全的。

5. 总结

  • TypeHandler 是 MyBatis 中用于处理类型转换的核心组件 ,通过自定义 TypeHandler 可以实现复杂的类型映射逻辑。

  • 使用步骤

    1. 创建自定义 TypeHandler
    2. 在实体类中指定 TypeHandler
    3. 在 MyBatis 配置中注册 TypeHandler(如果需要)。
  • 适用场景:基本类型与字符串的转换、复杂对象的序列化与反序列化等。

通过合理使用 TypeHandler,可以解决 MyBatis 中类型不匹配的问题,并增强代码的灵活性和可维护性。

参考:

可参考mybatis-plus 中的例子 com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler

相关推荐
绝无仅有14 小时前
某游戏互联网大厂Java面试深度解析:Java基础与性能优化(一)
后端·面试·架构
JaguarJack14 小时前
Laravel 新项目避坑指南10 大基础设置让代码半年不崩
后端·php·laravel
想不明白的过度思考者14 小时前
Rust——Trait 定义与实现:从抽象到实践的深度解析
开发语言·后端·rust
绝无仅有14 小时前
某短视频大厂的真实面试解析与总结(二)
后端·面试·架构
知了一笑14 小时前
项目效率翻倍,做对了什么?
前端·人工智能·后端
凤年徐14 小时前
Rust async/await 语法糖的展开原理:从表象到本质
开发语言·后端·rust
晨陌y15 小时前
从 “不会” 到 “会写”:Rust 入门基础实战,用一个小项目串完所有核心基础
开发语言·后端·rust
程序员爱钓鱼15 小时前
Python编程实战 - 函数与模块化编程 - 导入与使用模块
后端·python·ipython
程序员爱钓鱼15 小时前
Python编程实战 - 函数与模块化编程 - 匿名函数(lambda)
后端·python·ipython
Moment15 小时前
记录一次修改 PNPM 版本,部署 NextJs 服务时导致服务器崩溃的问题 😡😡😡
前端·javascript·后端