MyBatis(mybatis_plus)中TypeHandler的使用教程

MyBatis(mybatis_plus)中TypeHandler的使用教程

一.TypeHandler作用及其使用场景

在我们平常开发操作数据库时,查询、插入数据等操作行为,有时会报数据类型不匹配异常,就可以得知数据的类型是不唯一的必然是多种不同的数据类型。并且我们必须要明确的一点就是java作为一门编程语言有自己的数据类型,数据库也是有自己的数据类型的。

jdbc数据类型:org.apache.ibatis.type.JdbcType 此枚举就是所有的数据库支持类型

java数据类型:int、long、string、…

一定要分清,例如java重的date数据插入到数据库中,应该是已经转换成了数据库的某种类型,必然跟java已经没有关系了。中间有一些我们看不见的操作做了数据处理。

假设此时的java类型与数据库数据类型是一样的,哪么其他语言中的日期数据插入数据库时又该怎么解释,例如C#操作数据库存入时间类型,C#与java肯定没有关系吧。所以每种语言与数据库之间有种数据类型关系对应。

思考:

因为java与数据库各自有数据类型,所以在将java数据存入数据库前中间是否有其他操作,是我们看不见的,不然java数据怎么知道自己与哪个jdbc数据类型匹配?

答:mybatis框架为每种数据类型做了默认的关系对应,BaseTypeHandler的所有实现类,就是来做这些处理的。

例如:java中的date插入数据库时是jdbc哪种类型,怎么就是这种类型? 中间具体有什么操作?

答:DateTypeHandler就是来解决date数据类型的处理。

二.TypeHandler使用

我们想要自定义去处理Java和JDBC的数据类型转换时,需要实现TypeHandler接口,该接口源码如下:

//此接口作用是用于指定jdbc与java的数据类型间对应关系处理。
public interface TypeHandler<T> {
  // 保存操作,数据入库之前时数据处理
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  //下面三个则是,从数据库加载数据后,vo对象封装前的数据处理
  T getResult(ResultSet rs, String columnName) throws SQLException;
  T getResult(ResultSet rs, int columnIndex) throws SQLException;
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}

JsonIntegerTypeHandler 实现Integer和字符串互转

public class JsonIntegerTypeHandler extends BaseTypeHandler<Integer> {
    private static final ObjectMapper mapper = new ObjectMapper();

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

    @Override
    public Integer getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return this.toObject(rs.getString(columnName));
    }

    @Override
    public Integer getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return this.toObject(rs.getString(columnIndex));
    }

    @Override
    public Integer getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return this.toObject(cs.getString(columnIndex));
    }

    private String toJson(Integer params) {
        try {
            String copyObject = IotDbUtils.copyObject(params);
            return copyObject;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    private Integer toObject(String content) {
        if (content != null && !content.isEmpty()) {
            try {
                System.out.println("1111111111111"+content);
                return (Integer) mapper.readValue(content, Integer.class);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            return null;
        }
    }
}

Mapper.xml

查询

查询的时候 你转的那个字段就配置哪个字段

    <resultMap id="DmpDeviceReportResult" type="com.chinaunicom.iotdb.domain.DmpDeviceReportInformation" >
        <result column="Time" property="timestamp" />

        <result column="type" jdbcType="INTEGER"
                property="type" typeHandler="com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler"/>
        

    </resultMap>

  <select id="listDeviceReportInformation" resultMap="DmpDeviceReportResult">
        select trace_id, imei, topic, information, interaction_time,type
        from dmp_device_report_information
        where imei = #{serialNumber}
        <if test="beginTime != null and endTime != null">
            and interaction_time between #{beginTime} and #{endTime}
        </if>
        <if test="traceId != null and traceId != ''">
            and trace_id = #{traceId}
        </if>
        limit #{pageSize}  offset #{pageNum}
    </select>

新增

<insert id="add" parameterType="com.chinaunicom.iotdb.domain.DmpDeviceReportInformation">
        INSERT INTO root.device.dmp_device_report_information
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="null != type ">
                type,
            </if>
            <if test="null != traceId and '' != traceId">
                trace_id,
            </if>
            <if test="null != imei and '' != imei">
                imei,
            </if>
            <if test="null != topic and '' != topic">
                topic,
            </if>
            <if test="null != information and '' != information">
                information,
            </if>
            <if test="null != interactionTime  and '' != interactionTime ">
                interaction_time,
            </if>
            <if test="null != organizationId ">
                organization_id
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="null != type ">
                #{type,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
            <if test="null != traceId and '' != traceId">
                #{traceId,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
            <if test="null != imei and '' != imei">
                #{imei,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
            <if test="null != topic and '' != topic">
                #{topic,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
            <if test="null != information and '' != information">
                #{information,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
            <if test="null != interactionTime and '' != interactionTime ">
                #{interactionTime,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
            <if test="null != organizationId ">
                #{organizationId,typeHandler=com.chinaunicom.iotdb.handler.JsonIntegerTypeHandler },
            </if>
        </trim>
    </insert>

mybatisPlus中使用

类注解 @TableName(autoResultMap = true)
参数注解 @TableField(typeHandler = JsonIntegerTypeHandler.class)

@Data
@TableName(autoResultMap = true)
public class DmpDeviceReportInformation implements Serializable
{
    private static final long serialVersionUID = 1L;

    private Long id;

    /**
     * 消息类型1:消息上报 2:消息下发
     */
 @TableField(typeHandler = JsonIntegerTypeHandler.class)
    private Integer type;
    }

注意: 如果使用自己的mapper查询 要选择mybaits的形式

要想全局生效的话

mybatis-plus:
   type-handlers-package: com.chinaunicom.iotdb.handler
<think>我们正在讨论MyBatis-Plus中配置TypeHandler使用别名的问题。根据用户的问题,我们需要指导如何在MyBatis-Plus中为TypeHandler配置别名。在MyBatis中,TypeHandler用于处理Java类型和JDBC类型之间的转换。有时,我们可能希望为自定义的TypeHandler设置一个别名,以便在映射文件中方便地引用。在MyBatis-Plus中,我们可以通过多种方式配置TypeHandler,其中使用别名的方式与Mybatis类似。步骤:1.自定义TypeHandler:首先需要编写自己的TypeHandler,实现MybatisTypeHandler接口或继承BaseTypeHandler。2.为TypeHandler设置别名:在Mybatis的配置中,我们可以通过类型别名(typeAliases)来为TypeHandler设置别名。3.在映射文件中使用别名:在定义ResultMap或参数映射时,使用别名来引用TypeHandler。但是,在MyBatis-Plus中,我们通常使用注解配置,也可以使用XML配置。参考引用[1]中提到了配置mybatis-config.xml,因此我们可以考虑在mybatis-config.xml中配置别名。示例:步骤1:自定义TypeHandler例如,我们有一个自定义的TypeHandler用于处理List类型:```javapublic classListTypeHandler extendsBaseTypeHandler<List<String>>{//实现方法}```步骤2:在mybatis-config.xml中配置别名在<typeAliases>标签下,为TypeHandler设置别名: ```xml<typeAliases><!--其他别名配置--><typeAliastype="com.example.handler.ListTypeHandler"alias="ListTypeHandler"/></typeAliases> ```步骤3:在映射文件中使用在ResultMap中指定某个列使用这个TypeHandler:```xml<result column="tags" property="tags" typeHandler="ListTypeHandler"/>```另外,MyBatis-Plus也支持通过注解来配置TypeHandler。在实体类的字段上使用@TableField注解指定typeHandler: ```java@TableField(typeHandler =ListTypeHandler.class) privateList<String> tags; ```但是,这里直接使用了类名,并没有使用别名。那么,如果我们想用别名怎么办?实际上,在注解中不能直接使用别名,而是必须使用Class对象。因此,在注解方式下,我们无法使用别名。所以,使用别名主要是在XML映射文件中使用。另外,我们还可以在MyBatis-Plus的全局配置中通过配置typeHandler来注册,但这并不是别名的方式。注意:在MyBatis中,我们还可以通过扫描包的方式来注册TypeHandler,这样就不需要为每个TypeHandler单独配置别名。但是,如果我们需要在XML中引用,那么别名可以简化配置。总结:1.在XML配置中使用别名:在mybatis-config.xml中配置别名,然后在XML映射文件中使用别名引用TypeHandler。2.在注解方式下,无法使用别名,只能直接指定TypeHandler的类。因此,如果用户需要在XML映射文件中使用简短的别名来引用TypeHandler,可以按照上述步骤配置。参考引用[4]中提到了数据库连接的配置,虽然不直接相关,但提醒我们在配置数据库连接时要注意细节。生成相关问题:1.如何在MyBatis-Plus中自定义TypeHandler?2. MyBatis-Plus中如何配置全局的TypeHandler?3.在MyBatis-Plus中,如何通过注解方式指定TypeHandler?4.使用TypeHandler时,如何解决数据库时区问题(如引用[4]中提到的时区问题)?注意:用户的问题集中在“别名”的使用上,因此我们主要解答别名配置的方法。</think>### MyBatis-Plus 中配置 TypeHandler 使用别名的方法 在 MyBatis-Plus 中,通过别名配置 TypeHandler 需要以下步骤: #### 1. **自定义 TypeHandler** 首先创建自定义 TypeHandler 类(以处理 List<String> 类型为例): ```java public class ListTypeHandler extends BaseTypeHandler<List<String>> { @Override public void setNonNullParameter(...) { // 实现JDBC参数设置逻辑 } @Override public List<String> getNullableResult(...) { // 实现结果集转换逻辑 } } ``` #### 2. **配置别名(关键步骤)** 在 `mybatis-config.xml` 中注册别名: ```xml <typeAliases> <!-- 为TypeHandler设置别名 --> <typeAlias type="com.example.handler.ListTypeHandler" alias="ListHandler"/> </typeAliases> ``` #### 3. **在映射中使用别名** ##### 方式1:XML 映射文件 ```xml <resultMap id="userMap" type="User"> <result column="tags" property="tags" typeHandler="ListHandler"/> </resultMap> ``` ##### 方式2:注解方式(需结合 XML 别名) ```java public class User { @TableField(typeHandler = ListHandler.class) // 使用别名 private List<String> tags; } ``` #### 4. **全局配置(可选)** 在 MyBatis-Plus 配置类中全局注册: ```java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加其他拦截器... return interceptor; } // 注册TypeHandler @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> { configuration.getTypeHandlerRegistry().register(ListHandler.class); // 使用别名 }; } } ``` #### 注意事项: 1. **别名作用域** 别名仅在 MyBatis 配置文件作用域内有效,需确保别名在 `mybatis-config.xml` 中正确定义[^1]。 2. **依赖冲突** 如遇 `ClassNotFoundException`,检查是否缺少 `mybatis-typehandlers-jsr310` 等依赖(类似引用[3]中的依赖问题)。 3. **JDBC 参数** 数据库连接需正确配置参数,如 MySQL 时区设置(参考引用[4]): ```properties spring.datasource.url=jdbc:mysql:///db?serverTimezone=Asia/Shanghai ``` 4. **优先级规则** - 字段注解 > XML 映射 > 全局注册 - 自定义 TypeHandler 优先于内置处理器 > **最佳实践**:对于复杂类型处理,建议结合 `@MappedTypes` 和 `@MappedJdbcTypes` 注解声明处理器作用范围,减少显式配置。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值