深度分析MybatisPlus查询结果映射失败@TableField失效解决办法

 更新时间:2025年07月25日 09:31:58   作者:王ASC  
本文针对SpringBoot使用MybatisPlus框架时出现的查询结果映射失败问题进行深入分析,通过源码解析,阐述了@TableField注解失效的原因,并提出了四种有效的解决方案,感兴趣的朋友一起看看吧

问题场景

Springboot使用MybatisPlus框架,数据库中SQL能查到值,但是代码中查不到,出现All elements are null等问题。以下MybatisPlus简称MP

表结构

CREATE TABLE `camel`  (
  `pwd` varchar(255),
  `age` int(11)
);
INSERT INTO `camel` VALUES ('100', 0);
INSERT INTO `camel` VALUES ('200', 1);
INSERT INTO `camel` VALUES ('300', 2);
INSERT INTO `camel` VALUES ('400', NULL);

Java实体类

@TableName(value = "camel")
@Data
public class Camel {
    @TableField("pwd")
    private String pass_word;
    @TableField("age")
    private Integer age;
}

SpringBoot测试类

@SpringBootTest
class DemoApplicationTests {
    @Autowired
    CamelMapper camelMapper;
    @Test
    void testTableField() {
        // 构造查询条件 pwd > 100 的 LambdaQueryWrapper
        LambdaQueryWrapper<Camel> lambdaQueryWrapper = Wrappers.lambdaQuery(Camel.class)
                .gt(Camel::getPass_word, "100");
        List<Camel> list = camelMapper.selectList(lambdaQueryWrapper);
        list.forEach(System.out::println);
        assert list.get(0).getPass_word()!=null;
    }
}

执行结果

代码执行结果与预期不符,数据库中能查询到pwd,代码中查到的pass_word为NULL

先说原因

pass_word字段不满足命名规范,导致MP框架无法通过反射将查询字段赋值给实体类属性。

思考

数据从表中到实体类,可以理解为有两个阶段,首先是通过查询sql得到字段值,然后ORM框架将查询到的结果集通过setter的方式赋值给接收对象。

@TableField注解,用于使用MP动态生成SQL或用resultType接受自定义SQL结果集时,解决数据库字段名与实体类的属性名不一致时的问题,先前认为使用该注解就能结果上述问题。查看源码中MP给出的注释,如下

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {
    /**
     * 数据库字段值
     * <p>
     * 不需要配置该值的情况:
     * <li> 当 {@link com.baomidou.mybatisplus.core.MybatisConfiguration#mapUnderscoreToCamelCase} 为 true 时,
     * (mp下默认是true,mybatis默认是false), 数据库字段值.replace("_","").toUpperCase() == 实体属性名.toUpperCase() </li>
     * <li> 当 {@link com.baomidou.mybatisplus.core.MybatisConfiguration#mapUnderscoreToCamelCase} 为 false 时,
     * 数据库字段值.toUpperCase() == 实体属性名.toUpperCase() </li>
     */
    String value() default "";

当使用@TableField注解,执行sql如下:

select 注解值 as 实体类属性名 from table;

@TableField注解是通过别名实现的,其作用是当resultType为实体类时,自动为查询结果设置别名,是发生在查询阶段,也因此将控制台打印的sql拿到数据库中能正常执行,而本次问题是发生在用实体类接收查询结果阶段。

源码分析

容器启动后,MP会缓存Mapper实体类的setter与getter方法集合,这里使用了Lombok自动生成setter与getter

开始执行查询方法后,首先预编译PrepareStatement

当配置了Mybatis或MP的日志实现,控制台会打印预编译sql与参数,就是在这里实现的

预编译参数赋值,这里就是查询条件中的100

查询SQL执行完成,处理查询结果的映射关系

根据是否打开驼峰自动转换开关,处理属性名,注意这个开关在Mybatis中是默认关闭,而在MP中是默认打开的!所以在这里的pass_word被替换成了password

之后从容器启动时MP缓存的实体类的setter与getter方法集合中,查找实体类属性的setter方法,这里可以找到age,但是pass_word因被驼峰命名替换成password,而实际上实体类中的属性名是pass_word,导致无法找到password

用实体类中映射成功的字段接收查询结果,这里就只有age,没有password了

通过反射执行上面找到的属性的setter方法

只有符合命名规范的字段才会被赋值成功

最终接收查询结果的集合size = 3,但集合中只有两个元素,是因为SQL查出了3条记录,其中pwd=400的记录,因password字段赋值失败为NULL,且age也为NULL,该对象的所有属性都为NULL,所以集合中就存了一个NULL对象,如果集合中所有元素都是NULL,就会size != 0,且All elements are null

总结

MP通过反射的方式,使用属性对应setter方法为属性赋值,将查询结果映射到实体类,当属性命名不规范,且开启了驼峰命名开关,就会无法找到对应setter方法,导致属性无法赋值成功。

解决办法

方法一:手动添加setter方法

    private void setPassword(String pass_word) {
        this.pass_word = pass_word;
    }

方法二:若使用Lombok,规范属性命名(可以保留命名不规范的属性,避免影响项目原功能),本质与方法一相同

private String password;

方法三:在配置文件中关闭驼峰自动映射

mybatis-plus.configuration.map-underscore-to-camel-case=false

方法四:自定义Mapper方法,不使用实体类作为resultType,在xml中使用自定义resultMap,指定查询结果字段与实体类属性对应关系(没有使用resultType,@TableField注解不会生效)

    <!--property="pass_word"是实体类属性名,最终执行的setter方法是setPass_word-->
    <!--column="pwd"是查询结果字段名-->
    <resultMap id="myResultMap" type="com.example.demo.generator.domain.Camel">
        <result property="pass_word" column="pwd"/>
        <result property="age" column="age"/>
    </resultMap>
    <select id="myList" resultMap="myResultMap">
        select pwd, age from camel
    </select>  

参考

https://blog.csdn.net/HongYu012/article/details/123301153

到此这篇关于MybatisPlus查询结果映射失败@TableField失效解决办法【源码解析】的文章就介绍到这了,更多相关mybatisplus @tablefield失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot实现HTTP调用的7 种方式

    SpringBoot实现HTTP调用的7 种方式

    本文主要介绍了SpringBoot实现HTTP调用的7 种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04
  • SpringBoot配置actuator的代码

    SpringBoot配置actuator的代码

    这篇文章主要介绍了SpringBoot配置actuator,这里大家需要注意可以监控SpringBoot 中的 Tomcat 性能数据, 以日志形式定期输出监控数据, 只需要配置一个Bean,需要的朋友可以参考下
    2022-03-03
  • Spring Cloud Feign实现动态URL

    Spring Cloud Feign实现动态URL

    本文主要介绍了Spring Cloud Feign实现动态URL,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • ElasticSearch启动成功却无法在浏览器访问问题解决办法

    ElasticSearch启动成功却无法在浏览器访问问题解决办法

    因工作的需要,要使用elasticsearch,安装完了,启动也成功了之后发现了问题,这篇文章主要给大家介绍了关于ElasticSearch启动成功却无法在浏览器访问问题的解决办法,需要的朋友可以参考下
    2024-10-10
  • Springboot实现MQTT通信的示例代码

    Springboot实现MQTT通信的示例代码

    本文主要介绍了Springboot实现MQTT通信的示例代码,包含了MQTT协议的特点和工作原理等,具有一定的参考价值,感兴趣的可以了解一下
    2025-01-01
  • Eclipse中如何引入JUnit进行单元测试

    Eclipse中如何引入JUnit进行单元测试

    这篇文章主要介绍了Eclipse中如何引入JUnit进行单元测试问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • JavaEE中volatile、wait和notify详解

    JavaEE中volatile、wait和notify详解

    这篇文章主要给大家介绍了关于JavaEE中volatile、wait和notify的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-02-02
  • Java8中Stream API的peek()方法详解及需要注意的坑

    Java8中Stream API的peek()方法详解及需要注意的坑

    这篇文章主要给大家介绍了关于Java8中Stream API的peek()方法详解及需要注意的坑,Java 中的 peek 方法是 Java 8 中的 Stream API 中的一个方法,它属于中间操作,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • SpringBoot集成Eclipse Mosquitto的实现示例

    SpringBoot集成Eclipse Mosquitto的实现示例

    本文主要介绍了SpringBoot集成Eclipse Mosquitto的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-08-08
  • Java设计模式之单例模式Singleton Pattern详解

    Java设计模式之单例模式Singleton Pattern详解

    这篇文章主要介绍了Java设计模式之单例模式Singleton Pattern详解,一些常用的工具类、线程池、缓存,数据库,数据库连接池、账户登录系统、配置文件等程序中可能只允许我们创建一个对象,这就需要单例模式,需要的朋友可以参考下
    2023-12-12

最新评论