MyBatis的select标签的resultType属性

在MyBatis框架中,映射文件中select标签的resultType属性,用于指定从数据库查询返回结果集需要映射的Java类型,即Mapper接口中方法返回值类型(或集合中的泛型类型),可以是基本数据类型、基本数据类型的包装类型、自定义的PO类型、集合类型等类型。

一 基本类型和包装类

select标签的resultType属性指定基本数据类型,MyBatis会直接将结果列的值赋值给对应的变量,如果查询结果为空值或是其他类型无法转换成当前基本数据类型的值,那么MyBatis会抛出异常;

select标签的resultType属性指定基本数据类型的包装类型,MyBatis会将结果列的值转换为相应的包装类实例赋值给对应的变量,如果查询结果为空值,MyBatis会返回null,如果查询结果是其他类型,而且可以转换成当前基本数据类型的值,那么MyBatis会返回对应的值,否则会抛出异常;

创建一张成绩表,并插入一些数据,查询成绩的最值,接收数据库返回结果映射的Java类型,即resultType的类型分别使用基本数据类型和包装类型演示。

1.1 基本数据准备

创建score成绩表

CREATE TABLE `score` (
  `id` varchar(32) DEFAULT NULL,
  `username` varchar(32) DEFAULT NULL,
  `chinese` int DEFAULT NULL,
  `math` int DEFAULT NULL,
  `english` int DEFAULT NULL
) ENGINE=InnoDB 

表中插入数据,chinese、math和english的字段类型是int,模拟查询表中成绩的最大值

1.2 mapper接口

@Mapper
@Repository
public interface ScoreMapper {
    int getMaxEnglishIntScore();
    Integer getMaxEnglishIntegerScore();
}

1.3 mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mango.mapper.ScoreMapper">

    <select id="getMaxEnglishIntScore" resultType="int">
        select MAX(english) from score
    </select>

    <select id="getMaxEnglishIntegerScore" resultType="java.lang.Integer">
        select MAX(english) from score
    </select>

</mapper>

1.4 功能测试

1.4.1 表中字段类型是int

@SpringBootTest
@RunWith(SpringRunner.class)
public class ScoreTest {

    @Autowired
    private ScoreMapper scoreMapper;

    @Test
    public void testInt() {
        int maxEnglishIntScore = scoreMapper.getMaxEnglishIntScore();
        // int value is: 98
        System.out.println("int value is: " + maxEnglishIntScore);
    }

    @Test
    public void testInteger() {
        Integer maxEnglishIntegerScore = scoreMapper.getMaxEnglishIntegerScore();
        // Integer value is: 98
        System.out.println("Integer value is: " + maxEnglishIntegerScore);
    }

}

表中数据类型是int,而且表中也有数据,那么resultType指定的int类型,或Integer类型都可以查到数据

1.4.2 表中字段是空值

设置english字段的值都是空值

UPDATE score SET english = NULL

再执行测试代码

@SpringBootTest
@RunWith(SpringRunner.class)
public class ScoreTest {

    @Autowired
    private ScoreMapper scoreMapper;

    @Test
    public void testInt() {
        int maxEnglishIntScore = scoreMapper.getMaxEnglishIntScore();
        //==>  Preparing: select MAX(english) from score
        //==> Parameters:
        //<==    Columns: MAX(english)
        //<==        Row: null
        //<==      Total: 1

        // org.apache.ibatis.binding.BindingException:
        // Mapper method 'x.x.getMaxEnglishIntScore attempted to 
        // return null from a method with a primitive return type (int).
        System.out.println("int value is: " + maxEnglishIntScore);
    }

    @Test
    public void testInteger() {
        Integer maxEnglishIntegerScore = scoreMapper.getMaxEnglishIntegerScore();
        //==>  Preparing: select MAX(english) from score
        //==> Parameters:
        //<==    Columns: MAX(english)
        //<==        Row: null
        //<==      Total: 1

        // Integer value is: null
        System.out.println("Integer value is: " + maxEnglishIntegerScore);
    }

}

表中数据类型是int,而且表中数据为null,那么resultType指定的int类型要抛出异常,而resultType指定的Integer类型可以将null值赋值给指定的变量。这种情况下,两种类型执行SQL的情况是一样的:

==>  Preparing: select MAX(english) from score预编译sql
==> Parameters:   占位符对应的值
<==    Columns: MAX(english)表中的字段名称或别名
<==        Row: null表中字段的值
<==      Total: 1表总共返回多少行

resultType指定的int类型要抛出异常,org.apache.ibatis.binding.BindingException: Mapper method 'x.x.getMaxEnglishIntScore attempted to return null from a method with a primitive return type (int).

1.4.3 表中字段类型改为其他类型

1.4.3.1 改为字符串类型

将表中english字段类型设置为varchar

ALTER TABLE score MODIFY COLUMN english VARCHAR(20)

给表的english字段设置数字值

再执行测试代码

@SpringBootTest
@RunWith(SpringRunner.class)
public class ScoreTest {

    @Autowired
    private ScoreMapper scoreMapper;

    @Test
    public void testInt() {
        int maxEnglishIntScore = scoreMapper.getMaxEnglishIntScore();
        // int value is: 98
        System.out.println("int value is: " + maxEnglishIntScore);
    }

    @Test
    public void testInteger() {
        Integer maxEnglishIntegerScore = scoreMapper.getMaxEnglishIntegerScore();
        // Integer value is: 98
        System.out.println("Integer value is: " + maxEnglishIntegerScore);
    }

}

给表的english字段设置非数字值

 再执行测试代码,两种类型都会抛出异常:

1.4.3.2 改为其他类型

english字段改为bigint类型,也是可以获取值,只要不超过数据范围;

english字段改为double类型可以获取值,只会获取到整数部分,小数部分会舍弃掉;

二 自定义的PO类型

将MyBatis中select标签的resultType属性设置为自定义PO类型

2.1 实体类对象

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Score {
    private String id;
    private String username;
    private int chinese;
    private int math;
    private int english;
}

2.2 mapper接口

@Mapper
@Repository
public interface ScoreMapper {
    Score getScoreById(String id);
}

2.3 mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mango.mapper.ScoreMapper">

    <select id="getScoreById" resultType="com.mango.domain.Score">
        select id, username, chinese, math, english
        from score where id = #{id}
    </select>

</mapper>

2.4 功能测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class ScoreTest {

    @Autowired
    private ScoreMapper scoreMapper;

    // score is: Score(id=1001, username=a01, chinese=87, math=90, english=80)
    @Test
    public void testScore() {
        Score score = scoreMapper.getScoreById("1001");
        System.out.println("score is: " + score);
    }
}

==>    Preparing: select id, username, chinese, math, english from score where id = ? 
==> Parameters: 1001(String)
<==      Columns: id, username, chinese, math, english
<==             Row: 1001, a01, 87, 90, 80
<==             Total: 1

自定义实体类型,会从查询到的Columns中找匹配类中属性的字段,完成赋值操作,如果实体类中还有未匹配到字段的属性,那么属性取本身默认值(基本类型默认值,引用类型null值);

三 Map集合

将MyBatis中select标签的resultType属性设置为Map集合类型,将表中id是1001的记录,使用map集合存储以字段名为key,字段值为value的键值对

3.1 mapper接口

@Mapper
@Repository
public interface ScoreMapper {
    // Map<K,V>中的K指定String类型, V最好指定Object类型
    Map<String, Object> getMapValue(String id);
}

3.2 mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mango.mapper.ScoreMapper">

    <select id="getMapValue" resultType="java.util.Map">
        select id, username, chinese, math, english
        from score where id = #{id}
    </select>

</mapper>

3.3 功能测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class ScoreTest {

    @Autowired
    private ScoreMapper scoreMapper;

    @Test
    public void testScoreMap() {
        Map<String, Object> map = scoreMapper.getMapValue("1001");
        // scoreMap is: {chinese=87, english=80, id=1001, math=90, username=a01}
        System.out.println("scoreMap is: " + map);
    }
}

在Map集合中,也可以给查询的字段起别名,别名支持大小写。之前遇到过给字段取小驼峰别名,后来在map中对应的key的名字是小写的,没有复现出来这个问题。

四 List集合

如果接口中方法返回值类型是List集合,List集合的泛型类型可以是自定义PO类型或Map类型,那么在select标签的resultType属性中指定的类型仍然是自定义PO类型或Map类型。

4.1 mapper接口

@Mapper
@Repository
public interface ScoreMapper {
    List<Score> getScoreList();
    List<Map<String, Object>> getMapList();
}

4.2 mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mango.mapper.ScoreMapper">

    <select id="getScoreList" resultType="com.mango.domain.Score">
        select id, username, chinese, math, english
        from score
    </select>

    <select id="getMapList" resultType="java.util.Map">
        select id, username, chinese, math, english
        from score
    </select>

</mapper>

4.3 接口测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class ScoreTest {

    @Autowired
    private ScoreMapper scoreMapper;

    //[
    // Score(id=1001, username=a01, chinese=87, math=90, english=80),
    // Score(id=1002, username=b01, chinese=93, math=95, english=87),
    // Score(id=1003, username=b02, chinese=89, math=88, english=98),
    // Score(id=1004, username=c01, chinese=91, math=97, english=81),
    // Score(id=1005, username=c02, chinese=94, math=83, english=86)
    // ]
    @Test
    public void testScoreList() {
        List<Score> scoreList = scoreMapper.getScoreList();
        System.out.println(scoreList);
    }

    //[
    // {chinese=87, english=80, id=1001, math=90, username=a01}, 
    // {chinese=93, english=87, id=1002, math=95, username=b01}, 
    // {chinese=89, english=98, id=1003, math=88, username=b02}, 
    // {chinese=91, english=81, id=1004, math=97, username=c01}, 
    // {chinese=94, english=86, id=1005, math=83, username=c02}
    // ]
    @Test
    public void testScoreMapList() {
        List<Map<String, Object>> mapList = scoreMapper.getMapList();
        System.out.println(mapList);
    }

}

### MyBatis 中 `select` 标签的使用方法 #### 基本语法结构 `<select>` 是 MyBatis 映射文件中的一个重要标签,用于定义查询操作。其基本语法如下: ```xml <select id="statementId" resultType="resultTypeOrResultMap" parameterType="paramType"> SQL 查询语句 </select> ``` - **id**: 表示命名空间下的唯一标识符,供外部调用。 - **resultType**: 返回的结果集映射到 Java 对象的具体类路径或别名[^1]。 - **parameterType**: 输入参数的数据类型,可以是简单类型、POJO 或 Map 等[^3]。 --- #### 示例 1:单条件查询 假设有一个用户表 `UserInfo`,需要根据用户名模糊查询用户信息。 ##### Mapper 文件配置 ```xml <select id="selectUserInfoByName" resultType="com.java265.po.UserInfo" parameterType="string"> SELECT id, name, notes FROM UserInfo WHERE name LIKE CONCAT('%', #{name}, '%') </select> ``` ##### Mapper 接口方法 ```java public List<UserInfo> selectUserInfoByName(String name); ``` 此示例中,`#{name}` 被替换为传入的实际参数值,并自动处理 SQL 注入风险。 --- #### 示例 2:多条件查询 如果需要基于多个字段进行联合查询,则可以在 `<select>` 标签下加入更多条件。 ##### Mapper 文件配置 ```xml <select id="selectUserInfoByConditions" resultType="com.java265.po.UserInfo" parameterType="map"> SELECT id, name, notes FROM UserInfo WHERE name LIKE CONCAT('%', #{name}, '%') AND notes LIKE CONCAT('%', #{notes}, '%') </select> ``` ##### Mapper 接口方法 ```java public List<UserInfo> selectUserInfoByConditions( @Param("name") String name, @Param("notes") String notes); ``` 这里通过 `@Param()` 将方法参数绑定到 SQL 占位符上,便于动态传递参数。 --- #### 示例 3:复杂查询与分页支持 当涉及复杂的查询逻辑时,可以通过嵌套子查询或其他高级功能来增强灵活性。 ##### Mapper 文件配置 ```xml <select id="selectUsersWithPagination" resultType="com.java265.po.User" parameterType="map"> SELECT * FROM ( SELECT u.*, ROW_NUMBER() OVER (ORDER BY u.id ASC) AS rowNum FROM User u WHERE u.name LIKE CONCAT('%', #{name}, '%') AND u.sex = #{sex} ) tempTable WHERE rowNum BETWEEN #{startRow} AND #{endRow} </select> ``` ##### Mapper 接口方法 ```java public List<User> selectUsersWithPagination( @Param("name") String name, @Param("sex") String sex, @Param("startRow") int startRow, @Param("endRow") int endRow); ``` 这种写法适用于大数据量场景下实现分页查询[^4]。 --- #### 特殊情况:返回自增主键 在某些情况下,可能需要获取插入数据后的自动生成主键值。此时可通过 `useGeneratedKeys=true` 和 `keyProperty` 属性完成设置。 ##### Mapper 文件配置 ```xml <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO User(name, age) VALUES(#{name}, #{age}) </insert> <select id="getUserById" resultType="com.java265.po.User" parameterType="int"> SELECT * FROM User WHERE id = #{id} </select> ``` ##### Mapper 接口方法 ```java public void insertUser(User user); public User getUserById(int id); ``` 上述代码片段展示了如何利用 `useGeneratedKeys` 功能捕获数据库生成的主键并赋值给对象属性[^5]。 --- ### 总结 MyBatis 的 `<select>` 标签提供了强大的查询能力,能够满足从简单的单条件查询到复杂的多条件组合甚至带分页的功能需求。合理运用这些特性可以帮助开发者更高效地构建持久化层逻辑。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值