在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);
}
}