简介
本文用实例介绍MybatisPlus的分页以及多表联合查询的方法。
公共代码
分页插件新写法(3.4.0及之后)
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
@Configuration
public class MybatisPlusConfig {
// 分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
分页插件老写法(3.4.0之前)
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
// 分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
entity
@Data
@TableName("t_question")
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
// 问答主键id
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
// 学生外键id
@TableField("student_id")
private Integer studentId;
// 问题内容
private String content;
// 问题悬赏的积分
private Integer value;
}
@Data
@TableName("t_student")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
// 学生主键id
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
// 学生名称
private String name;
// 学生积分数
private Integer points;
}
VO
@Data
public class QuestionStudentVO implements Serializable {
// 问题主键id
private Integer id;
// 问题内容
private String content;
// 问题悬赏的积分
private Integer value;
// 学生外键id
private Integer studentId;
// 学生名字
private List<String> name;
// 学生积分
private Integer points;
}
启动类
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper")
public class MpPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MpPlusApplication.class, args);
}
}
sql
USE mp;
DROP TABLE IF EXISTS `t_question`;
CREATE TABLE `t_question` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`student_id` int(11) DEFAULT NULL,
`content` varchar(64) DEFAULT NULL,
`value` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8;
BEGIN;
INSERT INTO `t_question` VALUES ('1001', '1', 'this is question content', '10');
INSERT INTO `t_question` VALUES ('1002', '2', 'this is question content', '30');
COMMIT;
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student` (
`id` int(11) NOT NULL,
`name` varchar(64) DEFAULT NULL,
`points` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
BEGIN;
INSERT INTO `t_student` VALUES ('1', 'Iron Man', '201');
INSERT INTO `t_student` VALUES ('2', 'Jarvis', '100');
INSERT INTO `t_student` VALUES ('3', 'Tony', '300');
COMMIT;
分页插件
package com.example.conf;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
// 分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
多表查询
其他网址
mybatis Plus 多表联合查询
代码
mapper
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Question;
import com.example.vo.QuestionStudentVO;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface QuestionMapper extends BaseMapper<Question> {
@Select("SELECT t_question.*,t_student.`name`,t_student.`points` " +
" FROM t_question,t_student " +
" WHERE t_question.student_id=t_student.id")
List<QuestionStudentVO> getQuestionStudent();
@Select("SELECT t_student.name " +
" FROM t_question,t_student " +
" WHERE t_question.student_id = #{id} " +
" AND t_question.student_id=t_student.id")
List<String> getStudentNameByQuestionId(@Param("id") Long id);
@Select("SELECT t_student.name " +
" FROM t_question,t_student " +
" ${ew.customSqlSegment} " +
" AND t_question.student_id=t_student.id")
List<String> getStudentNamesByQuestionIds(@Param("ew") Wrapper wrapper);
}
controller
package com.example.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Student;
import com.example.mapper.QuestionMapper;
import com.example.vo.QuestionStudentVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.List;
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
private QuestionMapper questionMapper;
@RequestMapping("/getAllQuestionWithStudent")
public List<QuestionStudentVO> getAllQuestionWithStudent() {
List<QuestionStudentVO> questionStudent = questionMapper.getQuestionStudent();
if (questionStudent == null) {
return Collections.emptyList();
}
return questionStudent;
}
@RequestMapping("/getStudentNameByQuestionId")
public List<String> getStudentNameById(Long id) {
return questionMapper.getStudentNameByQuestionId(id);
}
@RequestMapping("/getStudentNamesByQuestionIds")
public List<String> getStudentNamesByQuestionIds(Long[] ids) {
List<Long> questionIds = Arrays.asList(ids);
return questionMapper.getStudentNamesByQuestionIds(questionIds);
}
}
测试
postman访问:http://localhost:8080/common/getAllQuestionWithStudent
postman结果
[
{
"id": 1001,
"studentId": 1,
"name": null,
"points": 201,
"content": "this is question content",
"value": 10
},
{
"id": 1002,
"studentId": 2,
"name": null,
"points": 100,
"content": "this is question content",
"value": 30
}
]
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@597f87ec] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1471701683 wrapping com.mysql.cj.jdbc.ConnectionImpl@7b7782db] will not be managed by Spring
==> Preparing: SELECT t_question.*,t_student.`name`,t_student.points FROM t_question,t_student WHERE t_question.student_id=t_student.id
==> Parameters:
<== Columns: id, student_id, content, value, name, points
<== Row: 1001, 1, this is question content, 10, Iron Man, 201
<== Row: 1002, 2, this is question content, 30, Jarvis, 100
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@597f87ec]
postman访问:http://localhost:8080/common/getStudentNameByQuestionId?id=1
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@427b93c6] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1287419385 wrapping com.mysql.cj.jdbc.ConnectionImpl@7b7782db] will not be managed by Spring
==> Preparing: SELECT t_student.name FROM t_question,t_student WHERE t_question.student_id = ? AND t_question.student_id=t_student.id
==> Parameters: 1(Long)
<== Columns: name
<== Row: Iron Man
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@427b93c6]
postman结果
[
"Iron Man"
]
postman访问:http://localhost:8080/common/getStudentNamesByQuestionIds?ids=1,2
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63dc1476] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1830549117 wrapping com.mysql.cj.jdbc.ConnectionImpl@7b7782db] will not be managed by Spring
==> Preparing: SELECT t_student.name FROM t_question,t_student WHERE (t_question.student_id IN (?,?)) AND t_question.student_id=t_student.id
==> Parameters: 1(Long), 2(Long)
<== Columns: name
<== Row: Iron Man
<== Row: Jarvis
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63dc1476]
postman结果
[
"Iron Man",
"Jarvis"
]
单表分页
其他网址
Mybatis-Plus官网(分页)
Mybatis Plus 使用详解 - 六层楼 -
代码
mapper
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Question;
import com.example.vo.QuestionStudentVO;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface QuestionMapper extends BaseMapper<Question> {
}
Service
package com.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.Student;
public interface StudentService extends IService<Student> {
}
package com.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.Student;
import com.example.mapper.StudentMapper;
import com.example.service.StudentService;
import org.springframework.stereotype.Service;
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
}
Controller
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
private QuestionService questionService;
@Autowired
private StudentService studentService;
@RequestMapping("/getAllStudent")
public IPage<Student> getAllStudent(Page<Student> page) {
// 如果查出来为空,会返回入参page里边的数据,比如:current,size等。不需要自己判空。
return studentService.page(page,
new LambdaQueryWrapper<Student>().orderByDesc(Student::getName)
);
}
@RequestMapping("/getAllStudentByName")
public IPage<Student> getAllStudentByName(Page<Student> page) {
// 如果查出来为空,会返回入参page里边的数据,比如:current,size等。不需要自己判空。
return studentService.lambdaQuery().eq(Student::getName, "Jarvis").page(page);
}
@RequestMapping("/getAllStudentByNameNo")
public IPage<Student> getAllStudentByNameNo(Page<Student> page) {
// 如果查出来为空,会返回入参page里边的数据,比如:current,size等。不需要自己判空。
return studentService.lambdaQuery().eq(Student::getName, "NO NO").page(page);
}
}
测试
postman访问:http://localhost:8080/common/getAllStudent
使用第1条(无条件,会查出所有)
postman结果
{
"records": [
{
"id": 1,
"name": "Iron Man",
"points": 201
},
{
"id": 2,
"name": "Jarvis",
"points": 100
},
{
"id": 3,
"name": "Tony",
"points": 300
}
],
"total": 3,
"size": 10,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"hitCount": false,
"searchCount": true,
"pages": 1
}
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5810d535] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1456943175 wrapping com.mysql.cj.jdbc.ConnectionImpl@61b976ac] will not be managed by Spring
JsqlParserCountOptimize sql=SELECT id,name,points FROM t_student
==> Preparing: SELECT COUNT(1) FROM t_student
==> Parameters:
<== Columns: COUNT(1)
<== Row: 3
==> Preparing: SELECT id,name,points FROM t_student LIMIT ?,?
==> Parameters: 0(Long), 10(Long)
<== Columns: id, name, points
<== Row: 1, Iron Man, 201
<== Row: 2, Jarvis, 100
<== Row: 3, Tony, 300
<== Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5810d535]
使用第2条(指定条件,有匹配到的):http://localhost:8080/common/getAllStudentByName?size=5¤t=1
postman结果
{
"records": [
{
"id": 2,
"name": "Jarvis",
"points": 100
}
],
"total": 1,
"size": 5,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"hitCount": false,
"searchCount": true,
"pages": 1
}
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6b8778dc] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@594281656 wrapping com.mysql.cj.jdbc.ConnectionImpl@61b976ac] will not be managed by Spring
JsqlParserCountOptimize sql=SELECT id,name,points FROM t_student
WHERE (name = ?)
==> Preparing: SELECT COUNT(1) FROM t_student WHERE (name = ?)
==> Parameters: Jarvis(String)
<== Columns: COUNT(1)
<== Row: 1
==> Preparing: SELECT id,name,points FROM t_student WHERE (name = ?) LIMIT ?,?
==> Parameters: Jarvis(String), 0(Long), 5(Long)
<== Columns: id, name, points
<== Row: 2, Jarvis, 100
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6b8778dc]
使用第3条(指定条件,没有匹配到的):http://localhost:8080/common/getAllStudentByNameNo
postman结果
{
"records": [],
"total": 0,
"size": 10,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"hitCount": false,
"searchCount": true,
"pages": 0
}
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6418d8d0] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1158294948 wrapping com.mysql.cj.jdbc.ConnectionImpl@61b976ac] will not be managed by Spring
JsqlParserCountOptimize sql=SELECT id,name,points FROM t_student
WHERE (name = ?)
==> Preparing: SELECT COUNT(1) FROM t_student WHERE (name = ?)
==> Parameters: NO NO(String)
<== Columns: COUNT(1)
<== Row: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6418d8d0]
多表分页
其他网址
最简单的 MyBatis Plus 的多表联接、分页查询实现方法_IT小村-
代码
Mapper
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Question;
import com.example.vo.QuestionStudentVO;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface QuestionMapper extends BaseMapper<Question> {
@Select("SELECT t_question.*,t_student.* " +
" FROM t_question,t_student " +
" WHERE t_question.student_id=t_student.id")
List<QuestionStudentVO> getQuestionStudentPage (Page<QuestionStudentVO> page);
}
Service
package com.example.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.Question;
import com.example.vo.QuestionStudentVO;
import java.util.List;
public interface QuestionService extends IService<Question> {
IPage<QuestionStudentVO> getQuestionStudentPage (Page<QuestionStudentVO> page);
}
package com.example.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.Question;
import com.example.mapper.QuestionMapper;
import com.example.service.QuestionService;
import com.example.vo.QuestionStudentVO;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {
//下边的this.baseMapper都可以用自动注入的QuestionMapper替换
@Override
public Page<QuestionStudentVO> getQuestionStudentPage (Page<QuestionStudentVO> page) {
return page.setRecords(this.baseMapper.getQuestionStudentPage(page));
}
}
Controller
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
private QuestionService questionService;
@Autowired
private StudentService studentService;
@RequestMapping("/getAllQuestionWithStudentByPage")
public IPage<QuestionStudentVO> getAllQuestionWithStudentByPage(Page<QuestionStudentVO> page) {
IPage<QuestionStudentVO> questionStudent = questionService.getQuestionStudentPage (page);
return questionStudent;
}
}
测试
postman访问:
http://localhost:8080/common/getAllQuestionWithStudentByPage?current=1&size=2
postman结果(可见数组或List无法直接赋值。)
{
"records": [
{
"id": 1001,
"studentId": 1,
"name": null,
"points": 201,
"content": "this is question content",
"value": 10
},
{
"id": 1002,
"studentId": 2,
"name": null,
"points": 100,
"content": "this is question content",
"value": 30
}
],
"total": 2,
"size": 2,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"hitCount": false,
"searchCount": true,
"pages": 1
}
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@46bd5ef7] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1676586413 wrapping com.mysql.cj.jdbc.ConnectionImpl@61b976ac] will not be managed by Spring
JsqlParserCountOptimize sql=SELECT t_question.*,t_student.* FROM t_question,t_student WHERE t_question.student_id=t_student.id
==> Preparing: SELECT COUNT(1) FROM t_question, t_student WHERE t_question.student_id = t_student.id
==> Parameters:
<== Columns: COUNT(1)
<== Row: 2
==> Preparing: SELECT t_question.*,t_student.* FROM t_question,t_student WHERE t_question.student_id=t_student.id LIMIT ?,?
==> Parameters: 0(Long), 2(Long)
<== Columns: id, student_id, content, value, id, name, points
<== Row: 1001, 1, this is question content, 10, 1, Iron Man, 201
<== Row: 1002, 2, this is question content, 30, 2, Jarvis, 100
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@46bd5ef7]
手动包装Page
Mybatis Plus分页查询的重点在于Page这个包装类。上边的多表分页查询用了page.setRecords其实就是手动包装的。再把代码拿过来看一下
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {
@Override
public Page<QuestionStudentVO> getQuestionStudentPage (Page<QuestionStudentVO> page) {
return page.setRecords(this.baseMapper.getQuestionStudentPage(page));
}
}
this.baseMapper.getQuestionStudentPage(page)
这个执行完之后,会将page的total等进行赋值。然后外部的page.setRecords会将其返回值设置到page里边去。
排序
排序涉及到Page类的List<OrderItem> orders;成员,OrderItem定义如下:
public class OrderItem implements Serializable {
private static final long serialVersionUID = 1L;
//需要进行排序的字段
private String column;
// 是否正序排列,默认 true
private boolean asc = true;
...
}
前端指定排序
Controller
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
private StudentService studentService;
@RequestMapping("/getAllStudentInOrder")
public IPage<Student> getAllStudentInOrder(Page<Student> page) {
IPage<Student> students = studentService.page(page);
if (students == null) {
return page;
}
return students;
}
}
测试
postman访问:http://localhost:8080/common/getAllStudentInOrder?current=1&size=2
postman的body
orders[0].column
orders[0].asc
postman的结果
{
"records": [
{
"id": 3,
"name": "Tony",
"points": 300
},
{
"id": 2,
"name": "Jarvis",
"points": 100
}
],
"total": 3,
"size": 2,
"current": 1,
"orders": [
{
"column": "name",
"asc": false
}
],
"optimizeCountSql": true,
"hitCount": false,
"searchCount": true,
"pages": 2
}
后端结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@551ee9d2] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@726462971 wrapping com.mysql.cj.jdbc.ConnectionImpl@61b976ac] will not be managed by Spring
JsqlParserCountOptimize sql=SELECT id,name,points FROM t_student
==> Preparing: SELECT COUNT(1) FROM t_student
==> Parameters:
<== Columns: COUNT(1)
<== Row: 3
==> Preparing: SELECT id, name, points FROM t_student ORDER BY name DESC LIMIT ?,?
==> Parameters: 0(Long), 2(Long)
<== Columns: id, name, points
<== Row: 3, Tony, 300
<== Row: 2, Jarvis, 100
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@551ee9d2]
后端OrderItems排序
@GetMapping("/page")
public IPage<User> getUserPage(Page<User> page) {
page.addOrder(OrderItem.desc("create_time"), OrderItem.asc("id"));
return UserService.page(page);
}
后端Wrapper排序
@GetMapping("/page")
public IPage<User> getUserPage(Page<User> page) {
LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery();
queryWrapper.orderByDesc(User::getCreateTime);
queryWrapper.orderByAsc(User::getId);
return UserService.page(page, queryWrapper);
}
其他网址
mybatis-plus的使用 ------ 进阶 -