【问题】Mybatis-plus框架使用@Select注解编写查询SQL,json字段查询转换失败

发布于:2025-08-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

问题描述

在使用mybaits-plus的时候定义的Mapper接口实现了BaseMapper,没有编写Mapper对应的xml,大部分查询使用框架的接口进行查询基本属性返回都是正常,复杂对象在sql中会进行查询,但是返回对象中却未包含相关属性。

问题原因

没有开启自动映射

实体类在使用@TableName 注解修饰时,在具有复杂对象的实体中没有开启autoResultMap 属性映射,这样在本身没有编写Mapper.xml的情况下会导致框架只会生成基础属性的映射,复杂对象不会处理,即使在复杂字段上标注了typeHandler = JacksonTypeHandler.class 也无济于事。

使用@Select注解自定义SQL

实体类开启了autoResultMap属性映射,但是在Mapper接口中使用@Select注解编写来进行查询。使用框架提供的查询方法复杂属性能正常返回,但是使用自定义查询复杂属性返回为空。

解决方案

未开启自动映射-开启自动映射

因为autoResultMap 默认是false的,如果实体对象中没有复杂属性,则不开也无所谓,mybatis-plus框架会将基础属性自动进行映射;但是如果实体使用了json,list等复杂属性,则需要显示开启自动映射,并且在@TableField中表明使用的handler类型,这样框架才会在查询出值之后知道怎么利用哪个handler来进行值的转换。

解决效果

库中的值

在这里插入图片描述

未开启自动映射查询结果
涉及的类
@TableName(value = "user_table")  
@Data  
public class UserEntity {  
  
  
    private String name;  
  
    private Integer age;  
  
    @TableField(value = "table_desc",typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.OTHER)  
    private List<String> tableDesc;  
  
}



@Mapper  
public interface UserEntityMapper extends BaseMapper<UserEntity> {  
}


//使用框架的查询
@RestController  
@RequestMapping("/test")  
public class TestController {  
  
  
    @Resource  
    UserEntityMapper userEntityMapper;  
  
    @GetMapping("/query")  
    public String getQuery(){  
        return JSONObject.toJSONString(userEntityMapper.selectList(null));  
    }  
  
}

查询结果
[ 
	{ "age": 4, "name": "123" }, 
	{ "age": 1, "name": "33333" } 
]
开启自动映射
涉及的类
  
@TableName(value = "user_table",autoResultMap = true)  
@Data  
public class UserEntity {  
  
  
    private String name;  
  
    private Integer age;  
  
    @TableField(value = "table_desc",typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.OTHER)  
    private List<String> tableDesc;  
  
}
查询结果
[ 
	{ "age": 4, "name": "123", "tableDesc": [ "age", "123" ] }, 
	{ "age": 1, "name": "33333", "tableDesc": [ "1123", "2131" ] } 
]

使用@Select自定义SQL-使用@ResultMap指定映射

使用@ResultMap的前提是开启了自动映射,这样框架生成的ResultMap对象中会包含我们指定对象的handler类,然后在@Select方法上添加@ResultMap注解,这样框架在执行自定义的SQL语句时就会知道使用哪个对象来进行数据转换。
@ResultMap注解中的值命名方式是 #{Mapper对象全路径}.mybatis-plus_#{实体类名}

未添加@ResultMap注解查询
涉及的类
@TableName(value = "user_table")  
@Data  
public class UserEntity {  
  
  
    private String name;  
  
    private Integer age;  
  
    @TableField(value = "table_desc",typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.OTHER)  
    private List<String> tableDesc;  
  
}

@Mapper  
public interface UserEntityMapper extends BaseMapper<UserEntity> {  
  
  
    @Select("select * from user_table ")
    List<UserEntity> getAllValue();  
  
}


@RestController  
@RequestMapping("/test")  
public class TestController {  
  
  
    @Resource  
    UserEntityMapper userEntityMapper;  

    @GetMapping("/query")  
    public String getQuery(){  
        return JSONObject.toJSONString(userEntityMapper.getAllValue());  
    }  
  
}


查询结果
[ 
	{ "age": 4, "name": "123" }, 
	{ "age": 1, "name": "33333" } 
]
添加@ResultMap注解
涉及的类
@Mapper  
public interface UserEntityMapper extends BaseMapper<UserEntity> {  
  

    @Select("select * from user_table ")
    //命名方式是 ${Mapper对象全路径}.mybatis-plus_${实体类名}
    @ResultMap("com.example.UserEntityMapper.mybatis-plus_UserEntity")
    List<UserEntity> getAllValue();  
  
}
查询结果
[ 
	{ "age": 4, "name": "123", "tableDesc": [ "age", "123" ] }, 
	{ "age": 1, "name": "33333", "tableDesc": [ "1123", "2131" ] } 
]

原理分析

1、执行SQL

org.apache.ibatis.executor.statement.PreparedStatementHandler#query方法中会执行SQL,获取查出的值
![[Pasted image 20250812212746.png]]

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyAutomaticMappings方法中主要是对属性进行转换,此时autoMapping只有两个基础字段的映射,并没有table_desc字段的映射
![[Pasted image 20250812213546.png]]

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createAutomaticMappings方法中会构造/获取当前方法相关的字段映射,key是方法方法全路径
![[Pasted image 20250812233354.png]]

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue方法中可以看到mybatis的configurationresultMaps对象中有4个键值对,其中

  • 以方法名命名的是是没有属性映射的,所以在执行时复杂属性获取不到映射就不会进行赋值
  • 以实体结尾的映射是由属性映射的,所以我们指定该值为@ResultMap内容就能对复杂对象进行赋值
    ![[Pasted image 20250812234742.png]]
    ![[Pasted image 20250812235009.png]]

网站公告

今日签到

点亮在社区的每一天
去签到