一、序言
(一)背景内容
软件应用技术架构中DAO层最常见的选型组件为MyBatis,熟悉MyBatis的朋友都清楚,曾几何时MyBatis是多么的风光,使用XML文件解决了复杂的数据库访问的难题。时至今日,曾经的屠龙者终成恶龙,以XML文件为基础的数据库访问技术变得臃肿、复杂,维护难度直线上升。
MybatisPlus对常见的数据库访问进行了封装,访问数据库大大减少了XML文件的依赖,开发者从臃肿的XML文件中获得了较大限度的解脱。
MybatisPlus官方并没有提供多表 连接查询 的通用解决方案,然而连接查询是相当普遍的需求。解决连接查询有两种需求,一种是继续使用MyBatis提供XML文件解决方式;另一种本文提供的解决方案。
事实上笔者强烈推荐彻底告别通过XML访问数据库,并不断探索新式更加友好、更加自然的解决方式,现分享最新的MybatisPlus技术的研究成果。
(二)场景说明
为了说明连接查询的关系,这里以学生、课程及其关系为示例。
(三)前期准备
此部分需要读者掌握以下内容:Lambda 表达式、特别是方法引用;函数式接口;流式运算等等,否则理解起来会有些吃力。
实体类与 Vo 的映射关系,作者创造性的引入特别构造器,合理利用继承关系,极大的方便了开发者完成实体类向 Vo 的转换。
空指针异常忽略不处理,借助 Optional 类实现,详情移步 Java8 新特性 查看。
二、一对一查询
一对一查询最典型的应用场景是将 id 替换成 name ,比如将 userId 替换成 userName 。
(一)查询单条记录
查询单条记录是指返回值仅有一条记录,通常是以唯一索引作为条件的返回查询结果。
1、示例代码
/**
* 查询单个学生信息(一个学生对应一个部门)
*/
public UserVo getOneUser(Integer userId) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
.eq(User::getUserId, userId);
// 先查询用户信息
User user = userMapper.selectOne(wrapper);
// 转化为Vo
UserVo userVo = Optional.ofNullable(user).map(UserVo::new).orElse(null);
// 从其它表查询信息再封装到Vo
Optional.ofNullable(userVo).ifPresent(this::addDetpNameInfo);
return userVo;
}
附属表信息补充
/**
* 补充部门名称信息
*/
private void addDetpNameInfo(UserVo userVo) {
LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class)
.eq(Dept::getDeptId, userVo.getDeptId());
Dept dept = deptMapper.selectOne(wrapper);
Optional.ofNullable(dept).ifPresent(e -> userVo.setDeptName(e.getDeptName()));
}
2、理论分析
查询单个实体共分为两个步骤:根据条件查询主表数据(需处理空指针异常);封装 Vo 并查询附属表数据。
查询结果(VO)只有一条记录,需要查询两次数据库,时间复杂度为 O(1) 。
(二)查询多条记录
查询多条记录是指查询结果为列表,通常是指以普通索引为条件的查询结果。
1、示例代码
/**
* 批量查询学生信息(一个学生对应一个部门)
*/
public List<UserVo> getUserByList() {
// 先查询用户信息(表现形式为列表)
List<User> user = userMapper.selectList(Wrappers.emptyWrapper());
List<UserVo> userVos = user.stream().map(UserVo::new).collect(toList());
// 此步骤可以有多个
addDeptNameInfo(userVos);
return userVos;
}</