MyBatis-plus是什么?
要解释Mybatis-plus那就必须先解释什么是mybatis:
(1)Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句 本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。程序员直接编写原生 态 sql,可以严格控制 sql 执行性能,灵活度高。
(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了 几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
(3)通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。(从执行 sql 到返回 result 的过程)。
看到这里大概了解了什么是mybatis,那么Mybatis-plus其实就是在mybatis只做增强,不做改变的增强框架,是中国人写的一个非常牛批的框架。这个框架让我们的开发更加简单,我们只需要在项目中添加相关依赖,在服务层实现一下接口就好了,这样一来减少了很多的SQL语句的编写,从而大大提高了开发效率。
mybatis-plus的入门案例
添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/>
</parent>
<dependencies>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!--springboot-test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</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>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
</dependencies>
application.properties
#新版本的mysql要设置时区,否则会报错,serverTimezone=GMT%2B8
spring.datasource.url=jdbc:mysql:///mybatis-plus?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
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=info
Employee实体类
@Setter
@Getter
@ToString
//表名注解:指定当前实体类映射哪张数据库表, 默认是跟实体类名一致
@TableName("t_employee")
public class Employee {
//主键注解:标记当前属性映射表主键。IdType.AUTO表示数据库ID自增
@TableId(value = "id",type = IdType.AUTO)
private Long id;
//字段注解:指定当前属性映射数据库表哪一列, 默认是跟属性名一致
@TableField("name")
private String username;
private String password;
private String email;
private int age;
private int admin;
private Long deptId;
}
EmployeeMapper
问题:没有编写crud的SQL语句,却可以执行crud操作?
思考:对mysql数据库中的数据进行crud肯定都需要依赖SQL,而代码中没有编写SQL语句,那么可以肯定mybatis-plus帮我们编写了
<!-- 以查询为例:selectById(1L) 要实现查询功能:必须拼接处SQL与条件 -->
<!--拼接SQL-->
select id,name,password......from employee
<!--条件参数-->
id:1L
mybatis-plus是如何实现上面操作:
1.spring容器启动后,Mybatis-plus就开始解析EmployeeMapper上面指定泛型类:Employee
2.通过反射解析Employee类,得到:
类名---->作为SQL 表名
属性---->作为SQL 列名
3.将解析出来的数据,根据调用的方法拼接处不同的SQL语句,然后执行
public interface EmployeeMapper extends BaseMapper<Employee> {
}
@Service
@Transactional
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
}
测试类代码:
//这里使用springboot的测试
@SpringBootTest
class EmployeeMapperTest {
@Autowired
private IEmployeeService employeeService;
@Test
public void save(){
Employee employee = new Employee();
employee.setName("James");
employee.setPassword("23");
employeeService.save(employee);
}
@Test
public void deleteById(){
employeeService.removeById(21);
}
@Test
public void update(){
Employee employee = new Employee();
employee.setId(21L);
employee.setName("Davis");
employee.setPassword("33");
employeeService.updateById(employee);
}
@Test
public void queryById(){
System.out.println(employeeService.getById(1));
}
}
通用mapper
使用建议:
知道id,并且所有更新使用字段updateById
注意:如果实体类中有基本数据类型,且更新时有默认值,mybatis-plus会认为他不为空,然后把数据库对应的列修改成了这个默认值
updateById
public void testUpdate1(){
Employee employee = new Employee();
employee.setId(3L);
employee.setName("dafei3");
employee.setPassword("123");
employee.setEmail("dafei3@xx.com");
employee.setAge(18);
employee.setAdmin(1);
employee.setDeptId(2L);
employeeMapper.updateById(employee);
}
部分字段更新,使用update:
用法:wrapper.条件.set需要更新的字段
update
//修改id为1的员工名字为James,password为789
public void testUpdate2(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id",1L)
.set("name","James")
.set("password","789");
employeeMapper.update(null,wrapper);
}
删除如何选用:
根据Id删除员工
deleteById
//需求:删除Id为3的员工
@Test
public void testDeleteById(){
employeeMapper.deleteById(3L)
}
根据满足一到多个条件的才删除
deleteByMap
//需求:删除name=李六明并且age=25的员工信息
@Test
public void testDeleteByMap(){
HashMap map = new HashMap();
map.put("name","李六明");
map.put("age",25);
employeeMapper.deleteByMap(map);
}
根据满足一到多个条件的才删除
delete
//需求:删除name=dafei并且age=18的员工信息
//delete from employee where name ='dafei' and age=18
@Test
public void testDeleteWrapper(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","xiaofei").eq("age",18);
employeeMapper.delete(wrapper);
}
批量删除
deleteBatchIds
//删除id为17 或 18 的员工
//delete from employee where id in(17,18)
@Test
public void testDeleteBatchIds(){
employeeMapper.deleteBatchIds(Arrays.asList(17,18));
}
根据Id查询
selectById
//需求:查询id为1的员工所有信息
//select * from employee where id= 1
@Test
public void testSelectById(){
System.out.println(employeeMapper.selectById(1));
}
批量查询
SelectBatchIds
//需求:查询id为4 或 5 或 6的员工所有信息
//select * from employee where id in(4,5,6)
@Test
public void testSelectBatchIds(){
System.out.println(employeeMapper.selectBatchIds(Arrays.asList(4,5,6)));
}
满足一个到多个条件才删除
selectByMap
//需求:查询name= James and age=40的员工信息
//select * from employee where name= 'James' and age=40
@Test
public void testSelectByMap(){
HashMap map = new HashMap();
map.put("name","James");
map.put("age",40);
System.out.println(employeeMapper.selectByMap(map));
}
查询满足某些条件的数据条数
selectCount
//需求: 查询满足(name = James)条件的所有的员工个数
@Test
public void testSelectCount(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","James");
System.out.println(employeeMapper.selectCount(wrapper));
}
查询满足某些条件的所有数据的集合(类型是:Employee)
selectList
//需求: 查询满足(name = James)条件的所有的员工
@Test
public void testSelectList(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","James");
System.out.println(employeeMapper.selectList(wrapper));
}
查询满足某些条件的所有数据的集合(类型是:Map<String, Object>)
selectMaps
应用场景:联表高级查询
//需求:查询满足条件的所有的员工信息, 返回List<Map<String, Object>> 底层将每条数据封装成HashMap
//SELECT id,name,age FROM employee WHERE (name = ?)
@Test
public void testSelectMaps(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","James");
wrapper.select("id,name,age");
List<Map<String, Object>> list = employeeMapper.selectMaps(wrapper);
list.forEach(System.out::println);
}
分页查询
selectPage
应用场景:单表分页高级查询
注意:在使用分页功能之前,一定要记得在启动类中配置好分页拦截器(MybatisPlusInterceptor),否则不起作用
@Test
public void testSelectPage(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
//参数1:当前页, 参数2:每页显示条数
IPage<Employee> page = new Page<>(1, 3);
employeeMapper.selectPage(page, wrapper);
System.out.println("当前页:" + page.getCurrent());
System.out.println("每页显示条数:" + page.getSize());
System.out.println("总页数:" + page.getPages());
System.out.println("总数:" + page.getTotal());
System.out.println("当前页数据:" + page.getRecords());
}
分页查询
selectMapsPage
应用场景:联表分页高级查询,等价于resultMap的使用
注意:在使用分页功能之前,一定要记得在启动类中配置好分页拦截器(MybatisPlusInterceptor),否则不起作用
//需求:查询第二页员工数据, 每页显示3条, (分页返回的数据是HashMap)
@Test
public void testSelectMapsPage(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
IPage<Map<String, Object>> page = new Page<>(2,3);
employeeMapper.selectMapsPage(page, wrapper);
System.out.println("当前页:" + page.getCurrent());
System.out.println("每页显示条数:" + page.getSize());
System.out.println("总页数:" + page.getPages());
System.out.println("总数:" + page.getTotal());
System.out.println("当前页数据:" + page.getRecords());
}
条件构造器
updateWrapper.set(“age”,18)
UpdateWrapper
该方法 等价于SQL片段: “set age = ?” =>paramter : 18 , 使用了占位符
//UpdateWrapper更新
//需求:将id=1的员工age改为18
@Test
public void testUpdate(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.set("age",18).eq("id",1L);
employeeMapper.update(null,wrapper);
}
LambdaUpdateWrapper
//LambdaUpdateWrapper更新
//需求:将id=1的员工age改为18
@Test
public void testLambdaUpdate1(){
LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(Employee::getId,1L)
.set(Employee::getAge,18);
employeeMapper.update(null,wrapper);
}
updateWrapper.setSql(“name =‘dafei’”)
该方法 等价于SQL片段: “name = ‘dafei’” 没有使用了占位符
//需求:将id=1的用户name改为dafei
@Test
public void testUpdate3(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id",1L);
wrapper.setSql("name ='dafei'");
employeeMapper.update(null,wrapper);
}
queryWrapper.select(“name”,“age”);
使用select方法指定需要查询的列,如果不设置会默认查询全部列(select *)
//需求:查询所有员工, 返回员工name, age列
@Test
public void testQuery1(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("name","age");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.orderByAsc(“age”)
按照员工年龄age正序排序,如果age一样, 按id正序排
//需求:查询所有员工信息按age正序排, 如果age一样, 按id正序排
@Test
public void testQuery3(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("age").orderByAsc("id");
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
}
queryWrapper.orderByDesc(“id”)
按照员工年龄age正序排序, 如果age一样, 按id倒序排序
//需求:查询所有员工信息按age正序排, 如果age一样, 按id倒序排序
@Test
public void testQuery5(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("age");
wrapper.orderByDesc("id");
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
}
优先级:优先级从上往下
queryWrapper.eq(“name”,“dafei”)
等价于: “where name=‘dafei’”
多个eq连用等价于 加了and关键字 :WHERE (name = “dafei” AND age = 18)
//需求:查询name=dafei, age=18的员工信息
//SELECT * FROM employee WHERE (name = ? AND age = ?)
@Test
public void testQuery6(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","dafei");
wrapper.eq("age",18);
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
}
queryWrapper.allEq(map)
使用map存放需要过滤的条件,并传入map对象调用allEq(全等)方法,查询满足map中所有条件的数据集合,该方法底层调用了另一个方法allEq(params, true),这里有个默认值为true,意思是如果当前key的value为null时会自动调用isNull方法。相反,如果自动设置为false的话,当前key的value为null时,该条件不会加到sql语句中去。
例1: allEq({id:1,name:“老王”,age:null})—>id = 1 and name = ‘老王’ and age is null
例2: allEq({id:1,name:“老王”,age:null}, false)—>id = 1 and name = ‘老王’
//需求:查询name=dafei, age=18的员工信息
//SELECT * FROM employee WHERE (name = ? AND dept_id IS NULL AND age = ?)
@Test
public void testQuery7(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
Map<String,Object>map = new HashMap<>();
map.put("name","dafei");
map.put("age",18);
map.put("dept_id", null);
wrapper.allEq(map);
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
}
//需求:查询name=dafei, age=18的员工信息
//SELECT * FROM employee WHERE (name = ? AND age = ?)
@Test
public void testQuery8(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
Map<String,Object>map = new HashMap<>();
map.put("name","dafei");
map.put("age",18);
map.put("dept_id", null);
wrapper.allEq(map,false);
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
}
queryWrapper.ne(“name”,“dafei”)
查询name != dafei员工信息
//需求:查询name != dafei员工信息
@Test
public void testQuery11(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.ne("name","dafei");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.gt(“age”,18)
查询age 大于18岁员工信息
//需求:查询age 大于18岁员工信息
@Test
public void testQuery12(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.gt("age",18);
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.lt(“age”,30)
查询age 小于18岁员工信息
//需求:查询age 小于30岁员工信息
@Test
public void testQuery12(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.lt("age",30);
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.ge(“age”,18)
查询age 大于等于18岁员工信息
//需求:查询age 大于等于18岁员工信息
@Test
public void testQuery12(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.ge("age",18);
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.le(“age”,30)
查询age 小于等于30岁员工信息
//需求:查询age 小于等于30岁员工信息
@Test
public void testQuery12(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.le("age",30);
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.isNull(“dept_id”)
查询dept_id 为null 员工信息
//需求: 查询dept_id 为null 员工信息
@Test
public void testQuery15(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.isNull("dept_id");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.isNotNull(“dept_id”)
查询dept_id 不为null 员工信息
//需求: 查询dept_id 为null 员工信息
@Test
public void testQuery15(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.isNotNull("dept_id");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.in(“id”,1,2)
查询id为1, 2 的员工信息,这种方式使用了占位符
//需求: 查询id为1, 2 的员工信息
@Test
public void testQuery17(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.in("id",1,2);
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.in(“id”,“1,2”)
查询id为1, 2 的员工信息,这种方式没有使用了占位符,是sql片段,一般推荐使用上面那种方式,可以防止sql注入
//需求: 查询id为1, 2 的员工信息
@Test
public void testQuery18(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.inSql("id","1,2");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.like(“name”,“fei”)
查询name中含有fei字样的员工
//需求: 查询name中含有fei字样的员工
@Test
public void testQuery19(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","fei");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.notLike(“name”,“fei”)
查询name中不含有fei字样的员工
//需求: 查询name中不含有fei字样的员工
@Test
public void testQuery20(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notLike("name","fei");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.likeLeft(“name”,“fei”)
查询name以fei结尾的员工信息 等价于 like “%fei”
//需求: 查询name以fei结尾的员工信息
@Test
public void testQuery21(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.likeLeft("name","fei");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.likeRight(“name”,“fei”)
查询姓王的员工信息 等价于 like “王%”
//需求: 查询姓王的员工信息
@Test
public void testQuery22(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.likeRight("name","王");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.or()
等价于 or关键字
//需求: 查询age = 18 或者 name=dafei 或者 id =1 的用户
@Test
public void testQuery23(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("age",18)
.or()
.eq("name","dafei")
.or()
.eq("id",1);
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.and()
等价于 and关键字
//需求:查询name含有fei字样的并且 年龄在小于18或者大于30的用户
@Test
public void testQuery26(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name", "fei")
.and(wr->wr.le("age",18)
.or()
.ge("age",30));
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.groupBy(“dept_id”)
以部门id进行分组查询,查每个部门员工个数
select 后面的列只能是 group by 后面中的列
//需求: 以部门id进行分组查询,查每个部门员工个数
@Test
public void testQuery27(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("id","count(*) count");
wrapper.groupBy("dept_id");
System.out.println(employeeMapper.selectList(wrapper));
}
queryWrapper.having(“count > {0}”,3)
这里的{0}是占位符
以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来
//需求: 以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来
@Test
public void testQuery28(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("id","count(*) count");
wrapper.groupBy("dept_id");
wrapper.having("count > {0}",3);
System.out.println(employeeMapper.selectMaps(wrapper));
}
通用方式
1:自定义服务接口集成IService接口
public interface IEmployeeService extends IService<Employee> {
}
/*2:服务接口实现类集成IService接口实现类ServiceImpl同时实现自定义接口
注意ServiceImpl实现类泛型:
泛型1:实体类的mapper接口
泛型2:实体类*/
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
}