前言
MybatisPlus
对于单表的操作很方便,但是多表查询等复杂的操作还是需要在xml
中写sql语句来完成。那么,在MybatisPlus
中如何实现多表联查、分页查询呢。
一、数据库表设计
我们模拟一个购物的情况,在数据库创建两个表,一个用户表,一个订单表。
用户表字段如下:
用户id、姓名、地址、deleted是一个假删除的字段,默认值是0,当对某个用户进行删除操作时将deleted的值0改为1。来标识某个数据被假删除了,查询的时候查不到,但是打开表数据还是存在的。
订单表字段如下:
订单id、数量、产品名、下单时间、更新时间、用户id
二、环境配置
1.引入依赖pom.xml
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok 简化set get toString -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
2.application.yml
3.实体类
User
private List<Order> orders;把order表的属性封装进一个几list集合里,用于实现多表联查。
@Data
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String address;
@TableLogic //逻辑删除
private Integer deleted;
@TableField(exist = false)//一对多
private List<Order> orders;
}
Order
@Data
@TableName("`order`")
public class Order {
@TableId("id")
private Long id;
private String number;
@TableField("product_name")
private String productName;
@TableField("order_time")
private LocalDateTime orderTime;
@TableField("update_time")
private LocalDateTime updateTime;
@TableField("u_id")
private Long uId;
public Long getuId() {
return uId;
}
}
5.UserConller
/**
* mybatisplus分页插件分页
* @param page
* @return
*/
@GetMapping("selectByPage")
public Page<User> selectByPage(Page <User> page) {
return userService.selectByPage(page);
}
6.UserService
public interface UserService extends IService<User> {
Page<User> selectByPage(Page <User> page)
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public Page<User> selectByPage(Page<User> page) {
return userMapper.selectByPage(page);
}
}
7.UserMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
//自定义方法
Page<User> selectByPage(@Param("page") Page <User> page);
}
8.OrderMapper
通过@Select注解,可以让开发人员在不写XML 配置文件的情况下,直接在接口方法中编写SQL语句,简化了开发流程。如下图
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
@Select("select * from `order` where u_id=#{uid}")
List<Order> selectByUserId(@Param("uid") Long uid);
}
这个例子中,@Select注解指定了SQL查询语句,其中#{uid}是参数占位符,标识方法参数中的uid变量。mybatis会自动将查询到的结果映射到返回值类型为LIst<order>的变量中。
9.xml文件
两个表连接条件是id=uid,通过xml文件里写的sql语句查询User 表中的所有记录,
<collection property="orders" column="id"得到用户id,
select="com.wedu.mapper.OrderMapper.selectByUserId"作为一个子查询,查询了order表里的数据,将得到的用户id传给@Select注解指定了SQL查询语句里的#{uid},从而得通过id=uid将两个表关联数据关联起来。
<?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.wedu.mapper.UserMapper">
<resultMap id="selectResultMap" type="com.wedu.entity.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="address" property="address"/>
<result column="deleted" property="deleted"/>
<!--
collection:一对多映射
property:要映射的实体类的属性名
ofType:指定映射属性类型
-->
<collection property="orders" column="id" ofType="com.wedu.entity.Order" select="com.wedu.mapper.OrderMapper.selectByUserId">
</collection>
</resultMap>
<select id="selectByPage" resultMap="selectResultMap">
SELECT
*
FROM
user u
</select>
三、测试
通过postman进行测试
current是当前页数、size是条数,通过修改这两个值进行分页。
{
"records": [
{
"id": 5,
"name": "王五",
"address": "北京",
"deleted": 0,
"orders": [
{
"id": 11,
"number": "6",
"productName": "手机",
"orderTime": "2024-08-12T21:09:13",
"updateTime": "2024-08-12T21:09:16",
"uId": 5
},
{
"id": 16,
"number": "4",
"productName": "玩偶",
"orderTime": "2024-08-14T09:09:28",
"updateTime": "2024-08-14T09:09:35",
"uId": 5
}
]
},
{
"id": 6,
"name": "赵六",
"address": "上海",
"deleted": 0,
"orders": [
{
"id": 14,
"number": "13",
"productName": "笔记本",
"orderTime": "2024-08-14T11:23:25",
"updateTime": "2024-08-14T11:23:30",
"uId": 6
}
]
}
],
"total": 9,
"size": 2,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"searchCount": true,
"countId": null,
"maxLimit": null,
"pages": 5
}
总结:
通过这个子查询实现的联表查询,得到的结果每个用户对应的订单不管有多少个分页时都算做一条数据,否则就会出现每个用户对应的订单号每有一个订单就算做一个数据,这样分页时同一个用户的不同订单就会被分散在不同页面。