类型引起的索引失效-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

相关推荐
zc.z几秒前
Windows版-RabbitMQ自动化部署
开发语言·后端
Victor35629 分钟前
Dubbo(43)如何排查Dubbo的服务版本冲突问题?
后端
bobz96531 分钟前
AI03 AI 的理念
后端
天南星1 小时前
java-springboot框架并发讨论-各层代码的并发问题
后端
乘云数字DATABUFF1 小时前
故障定位 | 服务&接口双粒度动态拓扑,精准定位共享连接池故障
后端
笑话_random1 小时前
云原生架构
后端·云原生
最后一次遇见2 小时前
weblog-module-admin(管理模块:后台的所有数据的物理逻辑都是在这里实现的)
后端
十分钟空间2 小时前
Flask+Bootstrap高可用框架搭建方案
后端
代码吐槽菌2 小时前
基于微信小程序的智慧乡村旅游服务平台【附源码】
java·开发语言·数据库·后端·微信小程序·小程序·毕业设计
阿里云云原生2 小时前
为什么我需要AI助手辅助学习python
后端