使用lombok注解导致mybatis-plus TypeHandler失效

这篇具有很好参考价值的文章主要介绍了使用lombok注解导致mybatis-plus TypeHandler失效。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题描述

建立实体其中一个字段为枚举类

/**
 * @author liuxishan 2023/6/2
 */
@Data
@Builder
@TableName(value = "hot_event",autoResultMap = false)
@EqualsAndHashCode(callSuper = true)
public class HotEvent extends BaseAuditor {
    @TableId(type = IdType.ASSIGN_ID)
    private String id;
   ············
   ············ 
    /**
     * 创建方式
     */
    @TableField(typeHandler = HotEventCreationMethodHandler.class,jdbcType = JdbcType.INTEGER)
    private CreationMethodEnum creationMethod;

}

public enum CreationMethodEnum {
    SYSTEM(0, "系统导入"),
    MANUAL_CREATE(1, "手动导入");

    /**
     * 用于排序
     */
    private Integer value;

    private String msg;

    CreationMethodEnum(Integer value, String msg) {
        this.value = value;
        this.msg = msg;
    }

    public Integer getValue() {
        return value;
    }

    public String getMsg() {
        return msg;
    }

    public static CreationMethodEnum valueOf(int value) {
        for (CreationMethodEnum creationMethodEnum : CreationMethodEnum.values()) {
            if (creationMethodEnum.value.equals(value)) {
                return creationMethodEnum;
            }
        }
        return null;
    }
}

希望数据库存的时对应的数字
为了和数据库进行转换,使用了typeHandler

public class HotEventCreationMethodHandler implements TypeHandler<CreationMethodEnum> {

    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, CreationMethodEnum creationMethodEnum, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i,creationMethodEnum.getValue());
    }

    @Override
    public CreationMethodEnum getResult(ResultSet resultSet, String columnName) throws SQLException {
        int anInt = resultSet.getInt(columnName);
        return CreationMethodEnum.valueOf(anInt);
    }

    @Override
    public CreationMethodEnum getResult(ResultSet resultSet, int i) throws SQLException {
        int anInt = resultSet.getInt(i);
        return CreationMethodEnum.valueOf(anInt);
    }

    @Override
    public CreationMethodEnum getResult(CallableStatement callableStatement, int i) throws SQLException {
        int anInt = callableStatement.getInt(i);
        return CreationMethodEnum.valueOf(anInt);
    }
}

测试发现

 @Test
    public void pageContents() {
      HotEvent hotEvent = HotEvent.builder()
                .eventName("测试事件名称")
                .eventOverview("测试测试")
                .eventType(EventTypeEnum.FUND)
                .bizId("1245454")
                .creationMethod(CreationMethodEnum.MANUAL_CREATE)
                .publishingTime(LocalDateTime.now())
                .url("http://baidu.com")
                .publishingAgency("机构")
                .build();
        hotEventDao.insert(hotEvent);
        List<HotEvent> hotEvents = hotEventDao.selectList(Wrappers.<HotEvent>lambdaQuery().eq(HotEvent::getCreationMethod, 1));
     
    }

插入/更新typeHandler生效,但是查询时在将数据库数据映射成java实体类的时候报错

Caused by: java.lang.IllegalArgumentException: No enum constant com.yiyouliao.rivers.content.api.enums.CreationMethodEnum.1
	at java.lang.Enum.valueOf(Enum.java:238)
	at org.apache.ibatis.type.EnumTypeHandler.getNullableResult(EnumTypeHandler.java:49)
	at org.apache.ibatis.type.EnumTypeHandler.getNullableResult(EnumTypeHandler.java:26)
	at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85)
	... 67 more

设置的HotEventCreationMethodHandler并没有生效
我们知道,在不开启autoResultMap时,会导致TableField对于查询返回的结果不生效。(对于更新无影响)
因此首先检查在实体类注解上已经开启了autoResultMap,仍然是报错(mybatisPlus会根据我们的实体类的类型,为我们自动注入resultMap,注入的resultMap也会自动推断出需要使用的类型转换器当然我们也可以指定)

@TableName(value = "hot_event",autoResultMap = true)

问题排查

网上查了typeHandler失效的原因,大部分都说的是检查autoResultMap。无奈只能跟源码进行检查
问题出在查询结果后将结果转换为java实体类的地方,由DefaultResultSetHandler进行处理
关键方法org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.lang.String)
在处理一行数据是,正常情况是首先创建java实体对象,然后根据resultMap的字段映射进行转换

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
   //创建java实体对象
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        if (shouldApplyAutomaticMappings(resultMap, false)) {
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
}

但是发现我们在createResultObject这一步就报错了,

Caused by: java.lang.IllegalArgumentException: No enum constant com.yiyouliao.rivers.content.api.enums.CreationMethodEnum.1

跟进去原因就找到了,在创建对象时
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.util.List<java.lang.Class<?>>, java.util.List<java.lang.Object>, java.lang.String)

 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }

这里有几种情况。

  1. 有对应typeHandler处理当前类型,由typeHandler根据resultSet创建
  2. 有constructorMappings(构造映射)我们没有设置
  3. 有默认无参构造,创建一个空对象,使用resultMap进行映射
  4. 无默认构造,那么根据构造函数,自动映射(不使用resultMap)进行映射

发现进了第四个处理逻辑导致报错,那么问题就发现了,是因为我们的实体类没有默认的无参构造函数

问题结论

回头检查实体类发现我们加了@Builder注解,会为实体类创建构造函数,但是也导致实体类没有了无参构造。
因此加上注解NoArgsConstructor,问题解决

/**
 * @author liuxishan 2023/6/2
 */
@Data
@Builder
@TableName(value = "hot_event",autoResultMap = false)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
public class HotEvent extends BaseAuditor {
    @TableId(type = IdType.ASSIGN_ID)
    private String id;
   ············
   ············ 
    /**
     * 创建方式
     */
    @TableField(typeHandler = HotEventCreationMethodHandler.class,jdbcType = JdbcType.INTEGER)
    private CreationMethodEnum creationMethod;

}

Tips

在查询时使用Wrappers构造查询条件时,查询字段是枚举时,不能直接使用枚举,需要使用数据库对应的值进行查询,因为typeHandler仅仅处理的是实体类字段和jdbcType的转换
错误写法

   List<HotEvent> hotEvents = hotEventDao.selectList(
       Wrappers.<HotEvent>lambdaQuery().eq(HotEvent::getCreationMethod, CreationMethodEnum.MANUAL_CREATE)
   );

正确写法文章来源地址https://www.toymoban.com/news/detail-469474.html

   List<HotEvent> hotEvents = hotEventDao.selectList(
       Wrappers.<HotEvent>lambdaQuery().eq(HotEvent::getCreationMethod,1)
   );

到了这里,关于使用lombok注解导致mybatis-plus TypeHandler失效的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Mybatis-Plus——05,乐观锁(新注解)

    乐观锁实现方式: 一、数据库添加一个字段 二、实体类添加@version注解 三、注册乐观锁插件 四、测试一下 4.1成功的乐观锁 version都是1 运行测试方法: 由1变为2 4.2失败的乐观锁 数据库的值为2 ———————— 创作不易,笔记不易,如觉不错,请三连,谢谢~~

    2024年03月09日
    浏览(53)
  • 【Mybatis-Plus】常见的@table类注解

    目录 引入Mybatis-Plus依赖 @TableName 当实体类的类名在转成小写后和数据库表名相同时 当实体类的类名在转成小写后和数据库表名不相同时 @Tableld @TableField 当数据库字段名与实体类成员不一致 成员变量名以is开头,且是布尔值  ​编辑 成员变量名与数据库冲突的时候 成

    2024年02月06日
    浏览(31)
  • 如何利用Mybatis-Plus自动生成代码(超详细注解)

    1、简介 MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 特性 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 损耗小:启动即会自动注入基本 CURD,性

    2024年02月01日
    浏览(32)
  • 2. 如何让mybatis-plus的逻辑删除注解@TableLogic临时失效

    1.1 controller代码 1.2 service层代码 1.3 entity代码 当我们正常调用接口时,sql查询日志为 数据库数据记录为: 接口调用结果为 可见逻辑删除注解已生效,is_del=1的小李没有查询出来 3.1 说明 我们让当前查询的逻辑删除失效时,不应影响其他查询活动,所以我们我们需要在线程上打

    2024年04月12日
    浏览(25)
  • 乌龙!mybatis-plus的@TableId注解不生效,原来竟是因为它!

    大家觉得下面的sql返回什么?   答案: 无返回。因为 null=1 是个false的表达式。这就像我们写 where 1=2 一样。   本次迭代的需求开发完成,将开发分支merge到test分支,部署测试环境提测后,QA提了一个bug,附下面log截图。 通过logtrace排查程序,定位到如下代码。代码很简单,

    2024年02月05日
    浏览(26)
  • SpringBoot+MyBatis-Plus多数据源@DS注解失效的解决方法

    引入 dynamic-datasource: application.yml 数据源配置: 详细使用请看 MyBatis-Plus官网 这种场景还是比较常见,比如在一个为master数据源的调用slave数据源就会失效 slave数据源Service方法 mater数据源Service方法调用slave数据源Service方法 这里会出现没有走slave_1,依然还是master数据源 需要在

    2024年01月18日
    浏览(42)
  • 【每日小bug】mybatis plus id注解错误导致的问题

    插入数据 id不为自增 指定了主键,没有指定自增。会导致出现 修改如上 报错 Data truncation: Out of range value for column ‘id’ at row 1 数据库是bigint,java中是Integer。 修改如上

    2024年01月16日
    浏览(27)
  • MyBatis-Plus 引入依赖导致的Error creating bean和java.lang.NoClassDefFoundError: com/baomidou/mybatisplus问题

     使用mybatis-plus出现的一些问题记录。 问题错误截图 问题原因: 依赖冲突 项目主pom文件中引入了mybatis-plus-boot-start依赖,版本为 3.5.3 业务包中引入mybatis-plus代码生成器依赖版本为 3.4.1 导致mybatis-plus-core核心包存在两个版本,导致冲突   解决办法 修改业务包中mybatis-plus代码

    2024年02月09日
    浏览(42)
  • 【MyBatis-Plus】MyBatis进阶使用

    目录 一、MyBatis-Plus简介 1.1 介绍 1.2 优点 1.3 结构 二、MyBatis-Plus基本使用 2.1 配置 2.2 代码生成 2.3 CRUD接口测试 三、MyBatis-Plus策略详解 3.1 主键生成策略 3.2 雪花ID生成器 3.3 字段自动填充策略 3.4 逻辑删除 四、MyBatis-Plus插件使用 4.1 乐观锁插件 4.1.1 什么是乐观锁和悲观锁? 4.

    2024年02月04日
    浏览(39)
  • Mybatis-plus 使用

            mybatis-plus提供了 ·@TableName·, @TableId, @TableField, @TableLogic 四种注解,其含义分别为:  @TableName          @TableName(\\\"SPF_Require_Vehicle\\\")    用于声明当前class所对应数据库中的表,如果class的名字和表的名字完全相同,则不需要添加该注解,如果不一样,则需要用该注解进

    2024年02月07日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包