本文章基于SpringBoot
Mybatis-plus
简介
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
优点
1>SQL语句自由控制,较为灵活
2>SQL与业务代码分离,易于阅读与维护
3>提供动态SQL语句,可以根据需求灵活控制
缺点
1>简单的crud操作也必须提供对应SQL语句
2>必须维护大量的xml文件
3>自身功能有限,要拓展只能依赖第三方插件
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.wolfcode</groupId>
<artifactId>mybatis-plus</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--SpringBoot版本-->
<version>2.4.3</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
<dependencies>
<!--mybatis plus苞米豆依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--springboot测试类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--小辣椒-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
配置4要素和日志
#mysql
spring.datasource.url=jdbc:mysql://localhost/mybatis-plus?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 配置slq打印日志
#logging.level.cn.wolfcode.mp.mapper=debug
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
常用注解
@TableName:
当表名与类名不一致时使用,做表名与类名映射
描述:表名注解
作用:指定当前实体类映射哪张数据库表, 默认是跟实体类名一致
@TableName("m_employee")
public class Employee {
@TableId:
在没有明确指定id生成规则时,默认使用雪花算法
描述:主键注解
作用:标记当前属性映射表主键。
其中:type属性指定主键类型
@TableId(value = "id",type = IdType.AUTO)
@TableField:
当列名与属性名不一致使用,做列名与属性名映射。(exist = false):表示该属性不与表中列进行映射
描述:字段注解(非主键)
作用:指定当前属性映射数据库表哪一列, 默认是跟属性名一致
其中:exist属性表示当前属性是否映射数据库列
@TableField(exist = false)
private Department dept;
通用Mapper接口
insert
// insert
// 需求:添加一条用户信息
// 插入一条记录
@Test
public void testSave(){
// 新建一个实体类并将数据存进去
Employee employee = new Employee("dafei", "111", "codeingMan@qq.com", 18, false, 1L);
employeeMapper.insert(employee);
}
update
updateById:
更新条件是id,并且是全量的
拼接规则:
1.实体对象参数属性有值,那么该属性名会拼接sql中
2.实体对象参数属性为基本属性,会有默认值,mybatis-plus认为是有值,参与SQL拼接
解决方案:
1.将基本类型改为包装类型
2.执行查询,再替换,后更新操作步骤
3.部分字段更新--(null,wrapper)
// updateById
// 需求: 将id=20用户名字修改为dafei
// 根据id对数据库进行修改
//1:先查
//2:替换
//3:更新
// 如果直接更新会导致数据丢失,因为updateById方法更新是整个更新的
@Test
public void testUpdateById(){
Employee employee = employeeMapper.selectById(20L);
employee.setName("dafei");
employeeMapper.updateById(employee);
}
update:
更新条件不仅限于id,并且部分列更新
// update
// 需求:更新name=dafei员工年龄为28岁
// 其中:使用UpdateWrapper中的eq方法添加条件,set方法设置改变值
// 注意: 拼接sql时,所有非null 字段都进行set 拼接
@Test
public void testUpdate1(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("name" , "dafei");
wrapper.set("age",28);
employeeMapper.update(null,wrapper);
}
// 需求:更新name=dafei,并且password=1111的员工年龄为18岁
@Test
public void testUpdate2(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("name","dafei").eq("password","1111").set("age",18);
employeeMapper.update(null,wrapper);
}
delete
// deleteById
// 需求:删除id=20的员工信息
@Test
public void testDeleteById(){
employeeMapper.deleteById(20L);
}
// deleteBatchIds
// 需求:删除id=20, id=21的员工信息
// DELETE FROM m_employee WHERE id IN ( ? , ? )
@Test
public void testBatchDelete(){
// 方法需要传入一个集合
employeeMapper.deleteBatchIds(Arrays.asList(20L,21L));
}
// deleteByMap
// 需求:删除name=dafei并且age=18的员工信息
// DELETE FROM m_employee WHERE name = ? AND age = ?
@Test
public void testdeleteByMap(){
// 该方法需要传入一个map集合
Map<String,Object> map = new HashMap<>();
map.put("name","dafei");
map.put("age",18);
employeeMapper.deleteByMap(map);
}
// delete
// 需求:删除name=dafei并且age=18的员工信息
// DELETE FROM m_employee WHERE (name = ? AND age = ?)
@Test
public void testDelete(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","dafei");
wrapper.eq("age",18);
employeeMapper.delete(wrapper);
}
select
// selectById
// 需求:查询id=1的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE id=?
@Test
public void testSelectById(){
System.out.println(employeeMapper.selectById(1L));
}
// selectBatchIds
// 需求:查询id=1,id=2的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE id IN ( ? , ? )
@Test
public void selectBatchIds(){
System.out.println(employeeMapper.selectBatchIds(Arrays.asList(1L, 2L)));
}
// selectByMap
// 需求: 查询name=dafei, age=18的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE name = ? AND age = ?
@Test
public void testSelectByMap(){
Map<String,Object> map = new HashMap<>();
map.put("name","dafei");
map.put("age",18);
employeeMapper.selectByMap(map);
}
// selectCount
// 需求: 查询部门号为5的所有的员工个数
// SELECT COUNT( 1 ) FROM m_employee WHERE (dept_id = ?)
@Test
public void testSelectCount(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("dept_id",5L);
System.out.println(employeeMapper.selectCount(wrapper));
}
// selectList
// 需求: 查询满足条件部门号为5的所有的员工信息, 返回List<Employee>
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (dept_id = ?)
@Test
public void testSelectList(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("dept_id",5L);
employeeMapper.selectList(wrapper).forEach(System.out::println);
}
selectMaps
当查询数据无法封装成对象时使用selectMaps
// selectMaps
// 需求: 查询满足条件部门号为5的所有的员工信息, 返回List<Map<String, Object>> 底层将每条数据封装成HashMap
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (dept_id = ?)
@Test
public void testSelectMaps(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("dept_id",5L);
employeeMapper.selectMaps(wrapper).forEach(System.out::println);
}
分页
// SelectPage
// 需求:查询第二页员工数据, 每页显示3条, (分页返回的数据是实体对象)
// 步骤1:配置分页插件,在启动类中配置分页拦截器
@SpringBootApplication
@MapperScan("cn.wolfcode.mp.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setOverflow(true); //合理化
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
// 步骤2:编写分页代码
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee LIMIT ?,?
@Test
public void testSelectPage(){
// IPage集合需要两个参数,一个是第几页,一个是每页显示多少条
IPage<Employee> page = new Page<>(2,3);
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
// 该方法需要两个参数,一个是Page集合,一个是Wrapper设置条件,无条件等价于null
IPage<Employee> iPage = employeeMapper.selectPage(page, wrapper);
System.out.println("当前页:" + iPage.getCurrent());
System.out.println("每页显示条数:" + iPage.getSize());
System.out.println("总页数:" + iPage.getPages());
System.out.println("总数:" + iPage.getTotal());
System.out.println("当前页数据:");
iPage.getRecords().forEach(System.out::println);
}
条件构造器
继承体系
更新操作
UpdateWapper
// UpdateWrapper:set
// 需求:将id=1的员工name改为dafei
// 注意:set方法中第一个参数是开关,true:执行该方法,false:不执行该方法
// UPDATE m_employee SET name=? WHERE (id = ?)
@Test
public void testUpdate1(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id",1L);
wrapper.set(true,"name","dafei");
employeeMapper.update(null,wrapper);
}
// UpdateWrapper:setSql
// 需求:将id=2的用户name改为dafei
// 注意:setSql方法中第一个参数是开关,true:执行该方法,false:不执行该方法
// UPDATE m_employee SET name = 'dafei' WHERE (id = ?)
@Test
public void testUpdate2(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id",2L).setSql(true,"name = 'dafei'");
employeeMapper.update(null,wrapper);
}
QueryWapper
// QueryWrapper
// 需求:查询name=dafei, age=18的用户
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name = ? AND age = ?)
@Test
public void testQuery1(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","dafei").eq("age",18);
employeeMapper.selectList(wrapper).forEach(System.err::println);
}
LambdaUpdateWrapper
// LambdaUpdateWrapper:set
// 需求:将id=3的员工name改为dafei
// 注意:set方法中第一个参数是开关,true:执行该方法,false:不执行该方法
// UPDATE m_employee SET name=? WHERE (id = ?)
@Test
public void testUpdate3(){
LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(Employee::getId,3L).set(true,Employee::getName,"dafei");
employeeMapper.update(null,wrapper);
}
LambdaQueryWrapper
// LambdaQueryWrapper
// 需求:查询name=dafei, age=18的用户
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name = ? AND age = ?)
@Test
public void testQuery2(){
LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(Employee::getName,"dafei").eq(Employee::getAge,18);
employeeMapper.selectList(wrapper).forEach(System.err::println);
}
高级查询
列投影:select
// select
// 需求:查询所有员工, 返回员工name, age列
// SELECT name,age FROM m_employee
@Test
public void testQuery1(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("name,age"); // SQL片段,是直接插入到SQL语句的
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// 需求:查询所有员工, 返回员工以a字母开头的列
// SELECT id,age,admin FROM m_employee
@Test
public void testQuery2(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select(Employee.class,f->f.getProperty().startsWith("a"));
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
排序
orderByAsc/orderByDesc
// orderByAsc
// 需求:查询所有员工信息按age正序排, 如果age一样, 按id正序排
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee ORDER BY age,id ASC
@Test
public void testQuery3(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("age,id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
//orderByDesc
// 需求:查询所有员工信息按age逆序排, 如果age一样, 按id逆序排
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee ORDER BY age,id DESC
@Test
public void testQuery4(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("age,id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
orderBy
// orderBy
// 需求:查询所有员工信息按age正序排, 如果age一样, 按id正序排
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee ORDER BY age,id ASC
@Test
public void testQuery5(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
// 第一个参数是开关,true:执行该方法,false:不执行该方法。
// 第二个参数是声明是否正序,true:正排序,false:逆排序
wrapper.orderBy(true,true,"age,id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// orderBy
// 需求:查询所有员工信息按age正序排, 如果age一样, 按id倒序排
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee ORDER BY age ASC,id DESC
@Test
public void testQuery6(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
// 第一个参数是开关,true:执行该方法,false:不执行该方法。
// 第二个参数是声明是否正序,true:正排序,false:逆排序
wrapper.orderBy(true,true,"age")
.orderBy(true,false,"id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
分组查询
groupBy
// groupBy
// 需求:以部门id进行分组查询,查每个部门员工个数
// 注意:一般group by 会配合count()来使用,不然会报错。
// SELECT dept_id,count(id) count FROM m_employee GROUP BY dept_id
@Test
public void testQuery7(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("dept_id,count(id) count");
wrapper.groupBy("dept_id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
having
// having
// 需求: 以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来
// SELECT dept_id,count(id) count FROM m_employee GROUP BY dept_id HAVING count > 3
@Test
public void testQuery8(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("dept_id,count(id) count").groupBy("dept_id") //.having("count > {0}",3);
.having("count > 3");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
条件查询
比较运算符
allEq/eq/ne
// allEq
// 需求:查询name=dafei, age=18的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name = ? AND age = ?)
@Test
public void testQuery9(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
Map<String,Object> map = new HashMap<>();
map.put("name","dafei");
map.put("age",18);
wrapper.allEq(map);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// 需求:查询满足条件员工信息, 注意传入的map条件中, 包含a的列才参与条件查询
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name = ? AND age = ?)
@Test
public void testQuery10(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
Map<String,Object> map = new HashMap<>();
map.put("name", "dafei");
map.put("age", 18);
wrapper.allEq((k, v)-> k.contains("a"), map);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// eq
// 需求:查询name=dafei员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name = ?)
@Test
public void testQuery11(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","dafei");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// ne
// 需求:查询name !=dafei员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name <> ?)
// <> 等价于 !=
@Test
public void testQuery12(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.ne("name","dafei");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
gt/ge/lt/le
// gt
// 需求:查询age 大于18岁员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age > ?)
@Test
public void testQuery13(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.gt("age",18);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// ge
// 需求:查询age 大于等于18岁员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age >= ?)
@Test
public void testQuery14(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.ge("age",18);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// lt
// 需求:查询age 小于18岁员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age < ?)
@Test
public void testQuery15(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.lt("age",18);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// le
// 需求:查询age 小于等于18岁员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age <= ?)
@Test
public void testQuery16(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.le("age",18);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
between/notBetween
// between
// 需求:查询年龄介于18~30岁的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age BETWEEN ? AND ?)
@Test
public void testQuery17(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.between("age",18,30);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// notBetween
// 需求:查询年龄小于18或者大于30岁的员工信息【用notBetween实现】
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age NOT BETWEEN ? AND ?)
@Test
public void testQuery18(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notBetween("age",18,30);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
isNull/isNotNull
// isNull
// 需求: 查询dept_id 为null 员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (dept_id IS NULL)
@Test
public void testQuery19(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.isNull("dept_id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// isNotNull
// 需求: 查询dept_id 为不为null 员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (dept_id IS NOT NULL)
@Test
public void testQuery20(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.isNotNull("dept_id");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
in/notIn/inSql/notInSql
// in
// 需求: 查询id为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (id IN (?,?))
@Test
public void testQuery21(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.in("id", Arrays.asList(1L,2L));
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// notIn
// 需求: 查询id不为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (id NOT IN (?,?))
@Test
public void testQuery22(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notIn("id", Arrays.asList(1L,2L));
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// inSql
// 需求: 查询id为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (id IN (1,2))
@Test
public void testQuery23(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.inSql("id","1,2");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// notInSql
// 需求: 查询id不为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (id NOT IN (1,2))
@Test
public void testQuery24(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notInSql("id", "1,2 ");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
模糊查询
like/notLike
// like
// 需求: 查询name中含有fei字样的员工
// 注意: 方法会自动帮我们在参数的前后加上%符号,无需我们添加
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name LIKE ?)
@Test
public void testQuery25(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","fei");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// notLike
// 需求: 查询name中不含有fei字样的员工
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name NOT LIKE ?)
@Test
public void testQuery26(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notLike("name","fei");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
likeLeft/likeRight
// likeLeft
// 需求: 查询name以fei结尾的员工信息
// 注意: likeLeft方法会已%为锚点,自动将%加在参数的左边
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name LIKE ?)
@Test
public void testQuery27(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.likeLeft("name","fei");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// likeRight
// 需求: 查询姓李的员工信息
// 注意: likeRight方法会已%为锚点,自动将%加在参数的右边
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name LIKE ?)
@Test
public void testQuery28(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.likeRight("name","李");
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
逻辑运算符
or
// or
// 需求: 查询age = 18 或者 name=dafei 或者 id =1 的用户
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age = ? OR name = ? OR id = ?)
@Test
public void testQuery29(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("age",18).or().eq("name","dafei").or().eq("id",1);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// 需求:查询name含有fei字样的,或者 年龄在18到30之间的用户,不能用between
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name LIKE ? OR (age >= ? AND age <= ?))
@Test
public void testQuery30(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","fei").or(
wp->wp.ge("age",18).le("age",30)
);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
and
// and : 默认是and操作
// 需求:查询年龄介于18~30岁的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (age >= ? AND age <= ?)
@Test
public void testQuery31(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.ge("age",18).le("age",30);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
// 嵌套and:
// 需求:查询name含有fei字样的并且 年龄在小于18或者大于30的用户
// SELECT id,name,password,email,age,admin,dept_id FROM m_employee WHERE (name LIKE ? AND (age < ? OR age > ?))
@Test
public void testQuery32(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","fei").and(
wp->wp.lt("age",18).or().gt("age",30)
);
employeeMapper.selectMaps(wrapper).forEach(System.err::println);
}
自定义SQL
mapper.xml方式
单表查询,关联查询
<--步骤1:在XxxMapper.xml中编写数据库语句-->
<mapper namespace="cn.wolfcode.mp.mapper.EmployeeMapper">
<resultMap id="BaseResultMap" type="cn.wolfcode.mp.domain.Employee" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="INTEGER" />
<result column="admin" property="admin" jdbcType="BIT" />
<result column="dept_id" property="deptId" jdbcType="BIGINT" />
<association property="dept" javaType="cn.wolfcode.mp.domain.Department" columnPrefix="d_">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="sn" property="sn"/>
</association>
</resultMap>
<select id="listByXmlSingle" resultMap="BaseResultMap">
select id, name, password, email, age, admin, dept_id from m_employee
</select>
<select id="listByXmlJoin" resultMap="BaseResultMap">
select e.id, e.name, e.password, e.email, e.age, e.admin, e.dept_id, d.id d_id, d.name d_name, d.sn d_sn
from m_employee e join m_department d on e.dept_id = d.id
</select>
</mapper>
//步骤2:在Mapper接口编写方法
// 单表
List<Employee> listByXmlSingle();
// 关联
List<Employee> listByXmlJoin();
// 自定义SQL语句
// 单表查询
//步骤3:编写测试类
@Test
public void testQuery33(){
employeeMapper.listByXmlSingle().forEach(System.err::println);
}
// 多表查询
@Test
public void testQuery34(){
employeeMapper.listByXmlJoin().forEach(System.err::println);
}
注解方式【拓展】
单表查询,关联查询
在Mapper接口的方法上贴上@Select注解和@Results注解
@Select("select e.* from m_employee e")
List<Employee> listByAnnoSingle();
@Select("select e.*, d.id d_id, d.name d_name, d.sn d_sn from m_employee e left join m_department d on e.dept_id = d.id")
@Results({
@Result(column="d_id", property = "dept.id"),
@Result(column="d_name", property = "dept.name"),
@Result(column="d_sn", property = "dept.sn")
})
List<Employee> listByAnnoJoin();
// 自定义SQL语句:注解方式
// 单表查询
@Test
public void testQuery35(){
employeeMapper.listByAnnoSingle().forEach(System.err::println);
}
// 多表查询
@Test
public void testQuery36(){
employeeMapper.listByAnnoJoin().forEach(System.err::println);
}
通用Service接口
通用方式
自定义接口:
自定义接口继承 IService 接口
明确指定泛型,当前接口操作实体对象:Employee
// 自定义服务接口继承IService接口
// 注意IService接口泛型:
// 泛型:实体类
public interface IEmployeeService extends IService<Employee> {
}
服务层接口实现类:
1.自定义一个类继承 ServiceImpl 实现自定义服务接口 IEmployeeService
2.在ServiceImpl上明确指定2两个泛型:
当前操作实体对象对应Mapper接口EmployeeMapper
当前操作实体对象Employee
// 实现类继承IService接口的实现类ServiceImpl同时实现自定义接口
// 注意ServiceImpl实现类泛型:
// 泛型1:实体类的mapper接口
// 泛型2:实体类
@Service
@Transactional
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
}
常用方法
getBaseMapper()
获取引用的XxxxMapper对象
// getBaseMapper:
// 获取当前接口引用的xxxMapper对象
@Test
public void testService1(){
employeeService.getBaseMapper().selectList(null).forEach(System.err::println);
System.out.println(employeeService.getBaseMapper() == employeeMapper);
}
getOne(wrapper)
指定条件查询单个, 结果数据超过1个报错
// getOne:
// 指定条件查询单个, 结果数据超过1个报错
@Test
public void testService2(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("id",1L);
System.out.println(employeeService.getOne(wrapper));
}
list(wrapper)
指定条件查询多个
// list:
// 指定条件查询多个
@Test
public void testService3(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","dafei");
employeeService.list(wrapper).forEach(System.err::println);
}
page(page, wrapper)
分页+高级查询
启动类:
//步骤1:配置分页插件
//分页
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setOverflow(true); //合理化
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
业务层XxxServiceImpl:
//步骤2:编写分页代码
@Override
public IPage<Employee> page(EmployeeQuery qo) {
IPage<Employee> page = new Page<>(qo.getCurrentPage(),qo.getPageSize());
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.hasText(qo.getKeyWord()),"name",qo.getKeyWord());
return super.page(page,wrapper);
}
测试类:
// 分页
// 需求:查询第2页员工信息, 每页显示3条
@Test
public void testPage1(){
EmployeeQuery query = new EmployeeQuery();
query.setCurrentPage(2);
query.setPageSize(3);
query.setKeyWord("fei");
IPage<Employee> iPage = employeeService.page(query);
System.out.println("当前页码:" + iPage.getCurrent());
System.out.println("每页显示数量:" + iPage.getSize());
System.out.println("总记录数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
System.out.println("数据:");
iPage.getRecords().forEach(System.err::println);
}