MybatisPlus出现Error attempting to get column ‘xxx字段‘ from result set异常解决

 更新时间:2023年11月29日 11:32:09   作者:段守志  
本文重点分析使用@EnumValue注解转换时遇到的一下错误原因,及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

MybatisPlus如何处理实体枚举类型转换的教程可以参考:点击查看教程,本文重点分析使用@EnumValue注解转换时遇到的一下错误原因,以及解决方案。

一、背景描述

在操作MybatisPlus的实体属性一般都是基本类型或者对应的引用类型或者String类型。但是MySQL8早已支持enum枚举类型,一直都没有实际操作过,于是想着有个枚举的场景打算实际项目里面用一下。当时在具体数据库表中设计了一个字段state来表示状态,这个状态有3个值:已入组已出组已移除。于是设计了这个字段为enum类型属性。但是在具体查询的时候出现如下的错误:

在这里插入图片描述

二、案例分析

当时具体场景比较简单就两个类:实体类枚举类

实体类(demo)

实体类的定义具体如下,重点关注属性:state

@Data
@EqualsAndHashCode
@TableName("demo")

public class Demo implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 身份证号
     */
    @TableField("id_card")
    private String idCard;

    /**
     * 受试者姓名
     */
    @TableField("`name`")
    private String name;

    /**
     * 联系电话
     */
    @TableField("phone")
    private String phone;

    /**
     * 入组时间
     */
    @TableField("join_time")
    private Date joinTime;

    /**
     * 状态:已入组、已出组、已移除
     */
    @TableField("state")
    private DemoStateEnum state;

    /**
     * 最近一次操作的用户
     */
    @TableField("last_user")
    private String lastUser;

    /**
     * 关联项目ID
     */
    @TableField("project_id")
    private Integer projectId;

    /**
     * 最后一次操作时间
     */
    @TableField("last_update")
    private Date lastUpdate;

    public static Demo builder(){
        return new Demo();
    }
}

枚举类(DemoStateEnum)

public enum DemoStateEnum {

    JOINED("已入组"),
    OUTED("已出组"),
    REMOVED("已移除");
    
    /**
     * 注意这个 @EnumValue注解一定要加上,否则SpringBoot启动都会报错,具体原因是因为MybatisePlus实现了根据这个注解表示实体属性自动枚举类型转换。如果找不到就会报错。
     */
    @EnumValue
    private String state;

    DemoStateEnum(String state){
       this.state = state;
    }
    
    /**
     * @JSONField这个注解解决alibaba.fastjson序列化是枚举显示的索引的值,而我们想要的显示是具体的值:已入组、已出组、已移除等。
     */
    @JSONField
    public String getState() {
        return state;
    }

    @Override
    public String toString() {
        return "DemoStateEnum{" +
                "state='" + state + '\'' +
                '}';
    }
}

表结构

CREATE TABLE `demo` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `id_card` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '身份证号',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '受试者姓名',
  `phone` varchar(13) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '联系电话',
  `join_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '入组时间',
  `state` enum('已入组','已出组','已移除') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '状态:已入组、已出组、已移除',
  `last_user` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近一次操作的用户',
  `project_id` int NOT NULL COMMENT '关联项目ID',
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后一次操作时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='枚举测试表';

三、单元测试

@SpringBootTest
public class DemoTest {

    @Autowired
    private DemoMapper deemoMapper;
    
    //查询所有demo数据
    @Test
    public void querySubject() throws JsonProcessingException {
        List<Demo> demos = deemoMapper.selectList(null);
        System.err.println(JSON.toJSONString(demos));
    }

}

执行以上单元测试会出现上面的错误,这里我就再贴一下图:

在这里插入图片描述

四、问题分析

# 根据上图细看这句话
Caused by: java.sql.SQLFeatureNotSupportedException
	at com.alibaba.druid.pool.DruidPooledResultSet.getObject(DruidPooledResultSet.java:1771)

找到DruidPooledResultSet.getObject()这个方法打上一个断点,然后根据idea的线程调用栈debug往上确定是由哪一步出现的异常。

在这里插入图片描述

如上图设置好debug点,开始运行上面的单元测试方法querySubject方法,监听断点:

在这里插入图片描述

那怎么知道上层是那个方法触发了这个异常呢,接着看左边的线程调用栈:可以看出黄色部分是上层真实异常的调用方。

在这里插入图片描述

基于以上我们继续往下分析,可以发现MybatisEnumTypeHandler#getNullableResult(java.sql.ResultSet, java.lang.String)这个方法里面的ResultSet的具体参数类型是一个DruidPooledResultSet,然后再调用DruidPooledResultSet类中的getObject(String columnLabel, Class type)方法。

public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
  throw new SQLFeatureNotSupportedException();
}

显然这个方法无论谁调用都是会抛出SQLFeatureNotSupportedException异常,那这样的话这个方法又有什么意义呢,于是猜想着是不是当前的druid是1.1.16(从下图可以看出版本依赖)版本太低导致无法适配当前查询场景,既然版本太低那就升级一下druid版本到1.1.21

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.21</version>
</dependency>

在这里插入图片描述

升级版本1.1.21继续尝试着运行,发现确实成功解决了。从下图可以看出druid版本成功升级从黄色区域可以看出来,那为什么可以解决当前问题呢?于是尝试进入同样的DruidPooledResultSet类中的getObject(String columnLabel, Class type)方法。发现1.1.16版本中的固定异常SQLFeatureNotSupportedException没有了,实现也完全不同了。如下:

public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
  try {
      // 正常调用JDBC中的ResultSet了,所以可以正常获取数据,不再出现那个异常了。
      return this.rs.getObject(columnLabel, type);
  } catch (Throwable var4) {
      throw this.checkException(var4);
  }
}

在这里插入图片描述

查询成功:

在这里插入图片描述

[{"id":4,"idCard":"666666","joinTime":"2023-08-09 15:21:13","lastUpdate":"2023-08-09 15:21:13","lastUser":"test user","name":"test name 6","phone":"123123123","projectId":2,"state":"已出组"},{"id":5,"idCard":"666666","joinTime":"2023-08-09 15:22:28","lastUpdate":"2023-08-09 15:22:28","lastUser":"test user","name":"test name 6","phone":"123123123","projectId":2,"state":"已出组"},{"id":6,"idCard":"666666","joinTime":"2023-08-09 15:24:00","lastUpdate":"2023-08-09 15:24:00","lastUser":"test user","name":"test name 6","phone":"123123123","projectId":2,"state":"已出组"}]

五、其他问题

alibaba.fastjson序列化枚举时候显示一个int值得问题,其实这个int值就是枚举中的ordinary也就是枚举列表中的索引。这个了解java枚举的应该都清楚枚举列表中的值都有自己对应的所有,而且底层也是存储在一个数组中的,也就是相当于数组的下表。但是不希望在序列化的时候显示这个下表,希望显示state的值。如何解决,在枚举的state属性的get方法加上如下@JSONField注解,这样就可以显示state的枚举值了。

    @JSONField
    public String getState() {
        return state;
    }

 到此这篇关于MybatisPlus出现Error attempting to get column ‘xxx字段‘ from result set异常解决的文章就介绍到这了,更多相关mybatis ‘xx‘ from result set内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Linux Ubuntu系统下配置JDK环境、MySQL环境全过程

    Linux Ubuntu系统下配置JDK环境、MySQL环境全过程

    众所周知Ubuntu是一种基于Linux的操作系统,它提供了一个稳定、安全和易于使用的环境,下面这篇文章主要给大家介绍了关于Linux Ubuntu系统下配置JDK环境、MySQL环境的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • Java list与set中contains()方法效率案例详解

    Java list与set中contains()方法效率案例详解

    这篇文章主要介绍了Java list与set中contains()方法效率案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java的Hello World详解

    Java的Hello World详解

    当我们学习一门编程语言的时候,我们都会先学如何输出Hello World!本文通过几个例子给大家介绍输出Hello World的代码,感兴趣的朋友一起看看吧
    2021-09-09
  • java使用hadoop实现关联商品统计

    java使用hadoop实现关联商品统计

    本篇文章java使用hadoop实现关联商品统计,可以实现商品的关联统计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-10-10
  • Springboot项目使用拦截器方法详解

    Springboot项目使用拦截器方法详解

    这篇文章主要介绍了Springboot项目使用拦截器方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • java实现自动售货机

    java实现自动售货机

    这篇文章主要为大家详细介绍了java实现自动售货机,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • java实现简易计算器功能

    java实现简易计算器功能

    这篇文章主要为大家详细介绍了java实现简易计算器功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • 代码实例Java IO判断目录和文件是否存在

    代码实例Java IO判断目录和文件是否存在

    本篇文章给大家分享了Java IO判断目录和文件是否存在的代码,对此有需要的读者们可以跟着小编一起学习下。
    2018-02-02
  • Jenkin邮件收发实现原理及过程详解

    Jenkin邮件收发实现原理及过程详解

    这篇文章主要介绍了Jenkin邮件收发实现原理及过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 详解Java如何利用反射提高代码的灵活性

    详解Java如何利用反射提高代码的灵活性

    反射是Java语言的一种特性,它允许程序在运行时动态地获取类的信息并操作类的属性、方法和构造函数,使得我们的代码更加灵活和可扩展,下面就来看看Java中反射机制的具体操作吧
    2023-05-05

最新评论