- Mybatis查询语句专题
- 返回Car
- 返回List<Car>
- 返回Map
- 返回List<Map>
- 查询结果列名和java对象属性名映射
十一、★★★Mybatis查询语句专题
- 准备工作:
- 模块名:
mybatis-008-select
- 打包方式:
jar
- 引入依赖:
mysql
驱动依赖、mybatis
依赖、logback
依赖、junit
依赖。 - 引入配置文件:
jdbc.properties
、mybatis-config.xml
、logback.xml
- 创建
pojo
类:Car
- 创建
Mapper
接口:com.f.mybatis.mapper.CarMapper
- 创建
Mapper
接口对应的映射文件:com/f/mybatis/mapper/CarMapper.xml
- 创建单元测试:
CarMapperTest
- 创建工具类:
SqlSessionUtil
- 模块名:
11.1 返回Car
当查询的结果,有对应的实体类,并且查询结果只有一条时:
1
2
3
4
5
6
7
8
9
10
11package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
Car selectById(Long id);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<select id="selectById" resultType="Car">
SELECT id,
car_num AS carNum,
brand,
guide_price AS guidePrice,
produce_time AS produceTime,
car_type AS carType
FROM t_car
WHERE id = #{id}
</select>
</mapper>1
2
3
4
5
6
7
8
public void testSelectById() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(2L);
System.out.println(car);
SqlSessionUtil.close(sqlSession);
}思考:如果查询结果是一条的话可以使用
List
集合接收吗?当然可以,只不过该
List
集合中只有一个Car
对象而已。- 反过来,如果查询结果不是一条记录,是多条记录的话,只采用单个实体类对象接收,这样就会出现下面的异常:
TooManyResultsException
。
- 反过来,如果查询结果不是一条记录,是多条记录的话,只采用单个实体类对象接收,这样就会出现下面的异常:
11.2 返回List<Car>
当查询的记录条数是多条的时候,必须使用集合接收。如果使用单个实体类接收会出现异常。
1
2
3
4
5
6
7
8
9
10
11
12
13package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
import java.util.List;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
List<Car> selectAll();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<select id="selectAll" resultType="Car">
SELECT id,
car_num AS carNum,
brand,
guide_price AS guidePrice,
produce_time AS produceTime,
car_type AS carType
FROM t_car
</select>
</mapper>1
2
3
4
5
6
7
8
public void testSelectAll() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectAll();
cars.forEach(car -> System.out.println(car));
SqlSessionUtil.close(sqlSession);
}
11.3 返回Map
**当返回的数据,没有合适的实体类对应的话,可以采用
Map
集合接收。字段名做key
,字段值做value
**。如果可以保证查询结果只有一条数据,则返回一个
Map
集合即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
import java.util.List;
import java.util.Map;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
Map<String, Object> selectByIdReturnMap(Long id);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<select id="selectByIdReturnMap" resultType="map">
SELECT id,
car_num AS carNum,
brand,
guide_price AS guidePrice,
produce_time AS produceTime,
car_type AS carType
FROM t_car
WHERE id = #{id}
</select>
</mapper>**
resultType
的完整类名应该是java.util.Map
,但是在 mybatis 框架内部内建了很多别名,java.util.Map
的别名就是map
,所以可以直接使用resultType="map"
**。1
2
3
4
5
6
7
8
9
10
public void testSelectByIdReturnMap() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Map<String, Object> result = mapper.selectByIdReturnMap(2L);
for (Map.Entry<String, Object> entry : result.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
SqlSessionUtil.close(sqlSession);
}思考:如果返回一个
Map
集合,那么可以将这个Map
集合放到List
集合中吗?当然可以。
- 反过来,如果返回的不是一条记录,是多条记录的话,只采用单个
Map
集合接收,这样同样会出现之前的异常:TooManyResultsException
。
- 反过来,如果返回的不是一条记录,是多条记录的话,只采用单个
11.4 返回List<Map>
如果查询结果条数大于等于 1 条数据,则可以返回一个存储
Map
集合的List
集合。List<Map>
类似于List<Car>
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
import java.util.List;
import java.util.Map;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
List<Map<String, Object>> selectAllReturnListMap();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<select id="selectAllReturnListMap" resultType="map">
SELECT id,
car_num AS carNum,
brand,
guide_price AS guidePrice,
produce_time AS produceTime,
car_type AS carType
FROM t_car
</select>
</mapper>resultType
还是map
。1
2
3
4
5
6
7
8
9
10
11
12
13
public void testSelectAllReturnListMap() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Map<String, Object>> results = mapper.selectAllReturnListMap();
results.forEach(result -> {
for (Map.Entry<String, Object> entry : result.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
System.out.println("==========");
});
SqlSessionUtil.close(sqlSession);
}
返回Map<String, Map>
对于
11.4
小节返回的List<<Map>
,取数据时比较麻烦,为了能快速取出想要的Map
集合,可以用Car
的id
做key
,对应的Map
集合做value
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;
import java.util.List;
import java.util.Map;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
/**
* 查询所有的Car,返回一个大Map集合
* 大Map集合的key是每条记录的主键值
* 大Map集合的value是每条记录的数据
* @return
*/
// 将查询结果的id值作为整个大Map集合的key
Map<Long, Map<String, Object>> selectAllReturnBigMap();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<select id="selectAllReturnBigMap" resultType="map">
SELECT id,
car_num AS carNum,
brand,
guide_price AS guidePrice,
produce_time AS produceTime,
car_type AS carType
FROM t_car
</select>
</mapper>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void testSelectAllReturnBigMap() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 返回的大Map
Map<Long, Map<String, Object>> results = mapper.selectAllReturnBigMap();
/**
* {
* 2={carType=混动, carNum=1111, guidePrice=100.00, produceTime=2023-10-12, id=2, brand=劳斯莱斯},
* 4={carType=新能源, carNum=1003, guidePrice=40.00, produceTime=2022-10-12, id=4, brand=问界}
* }
*/
System.out.println(results);
SqlSessionUtil.close(sqlSession);
}
11.5 ★查询结果列名和java对象属性名映射
查询结果的列名和 java 对象的属性名对应不上怎么办?
- 例如列名为
car_num
,java 对象属性名为carNum
。- 这是很正常的,因为在 mysql 中,字段命名用
_
进行分割;而在 java 中,属性命名用小驼峰命名方式。
- 这是很正常的,因为在 mysql 中,字段命名用
- 一但查询结果列名和 java 对象的属性名对应不上,就会出现 java 对象的相应属性无法赋值的问题,相应属性就会为 null。
- 例如列名为
有三种方式可以解决这个问题:
第一种方式:在 SQL 语句中使用
as
给列起别名。第二种方式:在
SqlMapper.xml
文件中使用resultMap
标签进行结果映射。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;
import java.util.List;
import java.util.Map;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
/**
* 查询所有Car的信息,使用resultMap标签进行结果映射
*
* @return
*/
List<Car> selectAllByResultMap();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<!-- 专门定义一个结果映射,在这个结果映射当中指定数据库表的字段名和Java类的属性名的对应关系 -->
<!--
1.type属性:用来指定POJO类的类名,全限定名称应该是com.f.mybatis.pojo.Car,
但是因为在mybatis-config.xml中设置了typeAliases中的包名,所以可以直接用Car(不区分大小写)
2.id属性:指定resultMap的唯一标识,这个id将来要在select标签中使用
-->
<resultMap id="carResultMap" type="Car">
<!-- 如果数据库表中有主键,建议这里配置一个id标签,
这样的配置可以让mybatis提高效率-->
<id property="id" column="id"/>
<!-- property后面填写POJO类的属性名 -->
<!-- column后面填写数据库表的字段名 -->
<result property="carNum" column="car_num"/>
<!-- <result property="brand" column="brand"/>
如果property和column的名字一样,就可以省略-->
<result property="guidePrice" column="guide_price"/>
<result property="produceTime" column="produce_time"/>
<result property="carType" column="car_type"/>
</resultMap>
<!-- select标签的resultMap属性,用来指定使用哪个结果映射。
resultMap后面的值是定义的resultMap的id -->
<select id="selectAllByResultMap" resultMap="carResultMap">
SELECT * FROM t_car
</select>
</mapper>1
2
3
4
5
6
7
8
public void testSelectAllByResultMap() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectAllByResultMap();
cars.forEach(car -> System.out.println(car));
SqlSessionUtil.close(sqlSession);
}第三种方式:在
mybatis-config.xml
文件中配置开启”驼峰命名自动映射”。使用这种方式的前提是:属性名遵循 Java 的命名规范,数据库表的列名遵循 SQL 的命名规范。
- Java 命名规范:首字母小写,后面每个单词首字母大写,遵循小驼峰命名方式。
- SQL命名规范:全部小写,单词之间采用下划线分割。
例如:
实体类中的属性名 数据库表的列名 carNum car_num carType car_type produceTime produce_time 如果要启用该功能,需要在
mybatis-config.xml
文件中进行配置:1
2
3
4<!--放在properties标签后面-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.f.mybatis.mapper;
import com.f.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;
import java.util.List;
import java.util.Map;
/**
* @author fzy
* @date 2024/1/10 15:29
*/
public interface CarMapper {
/**
* 查询所有Car的信息,但是启用了驼峰命名自动映射机制
*
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
}1
2
3
4
5
6
7
8
9
<mapper namespace="com.f.mybatis.mapper.CarMapper">
<select id="selectAllByMapUnderscoreToCamelCase" resultType="Car">
SELECT * FROM t_car
</select>
</mapper>1
2
3
4
5
6
7
8
public void testSelectAllByMapUnderscoreToCamelCase() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectAllByMapUnderscoreToCamelCase();
cars.forEach(car -> System.out.println(car));
SqlSessionUtil.close(sqlSession);
}