一、准备工作
-
创建新的模块: mybatis-008-select
-
该模块操作的还是 t_car 表,所以我们直接将之前的Car、jdbc.properties、SqlSessionUtil、logback.xml拿过来用
-
利用我们之前自制的idea模板创建核心配置文件和映射文件
-
我们在核心配置文件中 将pojo类统一起别名、并统一将所有的映射文件导入【映射文件与对应结构在一个目录下】
-
该模块整体的目录结构如下:
-
本篇概述:【查询的各种返回类型接收问题、起别名问题、查询数据总条数】
二、返回Car与List
- 概述:这部分的讨论都是通过三个文件来说明问题的【如何使用】
- 三个文件:映射文件Mapper、对应的接口、单元测试方法
🌔 1、标题有什么含义?
- 代表的是查询结果的两种封装方式
- Car 代表通过我们定义的pojo类的对象封装
- List 代表利用集合来封装我们的查询结果,List的类型为Car
🌔 2、通过几个案例来区别如何使用他们?
(1)根据 id 查询一条数据,返回 Car 的对象
接口中的方法:
/**
* 根据id查询汽车信息
* @param id
* @return
*/
Car selectById(Long id);
映射文件中的SQL语句:
<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>
测试类中的test方法:
@Test
public void testSelectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(27L);
System.out.println(car);
sqlSession.close();
}
测试结果: 成功显示我们根据 id 想要查询的汽车信息
(2)查询全部汽车数据,返回 List<Car>
的对象
接口中的方法:
/**
* 获取所有的汽车信息
* @return
*/
List<Car> selectAll();
映射文件中的SQL语句:
<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>
测试类中的test方法:
@Test
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));
sqlSession.close();
}
测试结果: 成功显示数据库表中的全部汽车信息
(3)根据品牌模糊查询,利用Car来接收查询结果
接口中的方法:
/**
* 根据品牌模糊查询
* 查询结果可能有多个,但是我们采用一个pojo对象来接收 >> 检测是否会产生问题
* 测试结果:TooManyResultsException异常
* @param brand
* @return
*/
Car selectByBrandLike(String brand);
映射文件中的SQL语句:
<select id="selectByBrandLike" 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
brand like "%"#{
brand}"%"
</select>
测试类中的test方法:
@Test
public void testSelectByBrandLike(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectByBrandLike("奔驰");
System.out.println(car);
sqlSession.close();
}
测试结果: 抛出TooManyResultsException异常,因为一个Car的对象不能接收多个查询结果
(4)根据id查询汽车数据,利用List来接收查询结果
接口中的方法:
/**
* 根据id查询汽车数据,然后用一个集合来接收
* 就是测试一条查询结果能不能用集合来接收
* 测试结果:必然是可以的
* @param id
* @return
*/
List<Car> selectById2(Long id);
映射文件中的SQL语句:
<select id="selectById2" 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>
测试类中的test方法:
@Test
public void testSelectById2(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectById2(28L);
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
测试结果: 测试成功,可以正常输出我们指定 id 的汽车信息
三、利用Map封装查询结果
🌔 1、在上面的内容无论是否采用集合的形式,我们都是通过pojo类来封装数据,那么如果没有合适的pojo类怎么办呢?
- 我们可以采用Map集合的方式来存储我们的查询结果
- key 对应表中字段名,value 对应属性值
- 一个 map 的对象可以存储一条数据记录
🌔 2、我们尝试根据 id 查询一条汽车信息,利用 Map 集合来接收查询结果【根据id查询只能获得一条记录】
接口中的方法:
/**
* 根据id查询汽车信息,将汽车信息封装到Map集合中
* @param id
* @return
*/
Map<String, Object> selectByIdRetMap(Long id);
映射文件中的SQL语句:
<!--此处封装查询结果的类型使用了 java.util.Map 的别名-->
<select id="selectByIdRetMap" resultType="map">
select * from t_car where id = #{
id}
</select>
测试类中的test方法:
@Test
public void testSelectByIdRetMap(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Map<String, Object> car = mapper.selectByIdRetMap(28L);
System.out.println(car);
sqlSession.close();
}
测试结果: 可以正常获得指定 id 的汽车信息
🌔3、如果查询结果为多条数据,我们可以用List集合嵌套Map集合来接收查询结果
接口中的方法:
/**
* 查询所有的Car信息,返回一个存放Map集合的List集合
* @return
*/
List<Map<String, Object>> selectAllRetListMap();
映射文件中的SQL语句:
<select id="selectAllRetListMap" resultType="map">
select * from t_car;
</select>
测试类中的test方法:
@Test
public void testSelectAllRetListMap(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Map<String, Object>> cars = mapper.selectAllRetListMap();
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
测试结果: 可以正常获得全部的汽车信息
🌔 4、采用这种方式如果我们想取一条指定id的记录很不方便,那是否可以采用其他存储结构呢?
- 我们可以采用大Map套小Map的形式,小Map和上面的一样
- 大Map的key我们可以存储表的主键,value可以通过map存储具体的一条记录信息
接口中的方法:
/**
* 查询所有的汽车信息,返回一个大Map集合
* Map集合的key是每条记录的主键[此处为id],value为每条记录
* 需要通过注解 @MapKey("主键名")指定大Map的key
* @return
*/
@MapKey("id")
Map<Long, Map<String, Object>> selectAllRetMap();
映射文件中的SQL语句:
<select id="selectAllRetMap" resultType="map">
select * from t_car;
</select>
测试类中的test方法:
@Test
public void testSelectAllRetMap(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Map<Long, Map<String, Object>> map = mapper.selectAllRetMap();
System.out.println(map);
sqlSession.close();
}
测试结果: 打印显示的是 key1 = value1, key2 = value2,…的形式
四、ResultMap结果映射
- 这部分主要阐述的是:如果表中字段名与类中属性名对不上,可以采用三种方法
- 方案一:在SQL语句中,我们直接通过关键字 as 来起别名 【不在此部分进行举例使用了】
- 方案二:在映射文件中通过 resultMap标签提前配置好别名,在SQL语句中使用 resultMap 声明即可
- 方案三:如果字段的命名和属性的命名都使用指定的规则,可以通过在核心配置文件中开启全局驼峰命名映射自动处理
🌔1、如果通过 resultMap 配置别名信息?
(1)找到我们的Mapper映射文件,在其中添加 resultMap 标签
<!--
我们需要提前在mapper标签中定义一个结果映射[数据库表中字段名——Java类属性名]
通过 type属性指定POJO类的类名[可以使用我们在核心文件中配置的别名],通过id属性定义resultType的唯一标识
-->
<resultMap id="carResultMap" type="Car">
<!--
在resultMap标签内部我们可以通过 result 标签来配置具体的别名信息
property属性指定我们在pojo类中的属性名
column属性指定了我们在数据库表中的字段名
-->
<!--主键值我们通过id标签配置,可以提高效率-->
<id property="id" column="id" />
<!--如果属性名和字段名一致,我们可以不配置-->
<result property="carNum" column="car_num" />
<result property="guidePrice" column="guide_price"/>
<result property="produceTime" column="produce_time" />
<result property="carType" column="car_type" />
<!--还可以指定javaType[属性名类型]和jdbcType[字段类型]可以提高效率-->
</resultMap>
(2)在上面代码段里我写了一些注解,在此提炼一下
-
id 代表我们这个映射的唯一标识,type 代表我们要对哪个pojo类进行映射【可以用别名】
-
对于主键我们最好用 id 标签声明,这样可以提高mybatis的效率
-
其余内部需要起别名的字段,我们通过 result 标签来完成
-
property 代表我们pojo类属性名
-
column 代表表中的列名
🌔2、如何使用我们配置的 resultMap 呢?
- 在写我们的 select 语句时,不需要指定 resultType,替换成 resultMap = “别名映射的id” 即可
<select id="selectAllByResultMap" resultMap="carResultMap">
select * from t_car
</select>
对应的测试程序:
@Test
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));
sqlSession.close();
}
对应的接口方法:
/**
* 查询所有的汽车信息,使用resultMap标签进行结果映射
* @return
*/
List<Car> selectAllByResultMap();
运行结果如下:
🌔 3、如何开启驼峰命名自动映射?
- 找到我们本模块的核心配置文件 mybatis-config.xml
- 在properties标签下面添加, settings 标签,在其内部配置具体的 setting 标签
<!--通过全局设置,开启驼峰映射代替起别名-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
-
使用驼峰命名自动映射机制有一个前提:属性名遵循Java命名规范、列名遵循SQL命名规范
-
Java 命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式
-
SQL 命名规范:全部小写,单词之间采用下划线分割
🌔 4、如何使用驼峰命名自动映射?
(1)开启驼峰命名自动映射机制,编写接口方法
/**
* 查询全部汽车数据,但是启用了驼峰命名自动映射机制
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
(2)编写SQL语句
<select id="selectAllByMapUnderscoreToCamelCase" resultType="Car">
select * from t_car
</select>
(3)编写测试程序
@Test
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));
sqlSession.close();
}
(4)运行测试 >> 可以正常使用
🌔 5、补充知识点:统计表中所有数据的条数
接口方法:
/**
* 获取汽车信息的总记录条数
* @return
*/
Long selectTotal();
SQL 语句: 如果count指定的列名,那么如果存在空就不会统计当前这条数据
<select id="selectTotal" resultType="long">
select count(*) from t_car
</select>
测试结果: 统计成功