MyBatisPlus
1.1MyBatisPlus简介
MyBatisPlus是基于MyBatis的框架的基础上开发的增强型工具,它简化开发,将一些增删改查的写好封装到BaseMapper,你只需要继承BaseMapper,就可以调用其的方法,一些简单的sql语句不在用手动编写,可以与MyBatis配合使用,提升工作效率。
MyBatis官网: MyBatis-Plus (baomidou.com)
MyBatisPlus特性(官方网站):
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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.2MyBatisPlus入门程序
MyBatisPlus可以和spring、springMVC、springBoot进行整合使用,应为在大多数开发中使用springBoot框架的居多,所以我们使用springBoot来整合MyBatisPlus。
我们要在pom.xml文件中导入MyBatisPlus依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
我在这个入门程序中使用的是Druid数据源,所以我们也要导入Druid数据源的依赖(SpringBoot&整合Druid数据源: SpringBoot&整合Druid数据源_springboot 整合druid_一路向北…的博客-CSDN博客 )
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
application.yaml配置
spring:
datasource:
username: root
password:
url: jdbc:mysql://localhost:3306/dbs?&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#开启MyBatisPlus的日志(输出到控制台)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
我的数据库表
在springBoot项目中创建实体类,我使用了lombok,可以简化实体类中的操作
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
Student
package com.gao.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
private int age;
private int cid;
}
在dao层中创建接口来实现增删改查方法,用来继承BaseMapper类。其中BaseMapper的类型为你的实体类,在BaseMapper中封装许多的增删改查方法,可以根据自己的需求进行调用。
StudentDao
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gao.pojo.Student;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StudentDao extends BaseMapper<Student> {
}
在测试类中进行测试,就可以输出结果了。
Demo01ApplicationTests
import com.gao.dao.StudentDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Demo01ApplicationTests {
@Autowired
StudentDao studentDao;
@Test
void contextLoads() {
//查询所有的方法
System.out.println(studentDao.selectList(null));
}
}
1.3MyBatisPlus分页查询定制
我们找到selectPage方法发现,它需要一个Page对象
在selectPage的源代码中可以看到这个Page对象是一个IPage的对象
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
IPage是一个接口,需要有一个是实现类,IPage接口只有一个实现类Page
@Test
void page(){
// 页码设置:当前第一页每页2条
IPage page = new Page(1,2);
studentDao.selectPage(page,null);
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());
}
但是我们只用次方法是不能实现分页查询的,我们只能查询出表的全部数据,我们要配置一个MyBatisPlus的拦截器,拦截并开启一个分页拦截器,此操作类似于AOP。
在Config层创建StudentConfig来配置拦截器
StudentConfig
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class StudentConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//1.定义MyBatisPlus拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//添加具体的拦截器 (在这里可以根据自己的需求添加不同的拦截器)
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
当我们完成拦截器的配置后,我们的分页查询功能就可以实现了。
1.4DQL编程控制
1.1条件查询三种格式
// 按条件查询
@Test
void test1(){
//方式一:按条件查询
QueryWrapper qw = new QueryWrapper();
qw.lt("age",29);
List<Student> list = studentDao.selectList(qw);
System.out.println(list);
}
//按条件查询
@Test
void test2(){
//方式二:lambda格式按条件查寻
QueryWrapper<Student> qw = new QueryWrapper();
qw.lambda().lt(Student::getAge,31);
List<Student> list = studentDao.selectList(qw);
System.out.println(list);
}
@Test
void test3(){
//方式三
LambdaQueryWrapper<Student> lqw = new LambdaQueryWrapper<>();
//小于29大于10
lqw.lt(Student::getAge,30).gt(Student::getAge,10);
//小于10大于29
//lqw.lt(Student::getAge,10).or().gt(Student::getAge,29);
List<Student> list = studentDao.selectList(lqw);
System.out.println(list);
}
1.2查询投影
查询投影是指你查询出的数据有的个字段。
//查询投影
@Test
void test4(){
LambdaQueryWrapper<Student> lqw = new LambdaQueryWrapper<>();
//只查询getId、getName两个字段数据
lqw.select(Student::getId,Student::getName);
List<Student> list = studentDao.selectList(lqw);
System.out.println(list);
}
从输出的结果和sql语句可以看出,查询得到的字段只有ID和name,查询投影可以用来单独查询一个表中一个或多个字段。
注意:
lqw.select(Student::getId,Student::getName);此种格式只适用lambda格式,如果使用QueryWrapper的方式就需要字符串的形式qw.select(“id,name”);
查询投影也可以用来做分组统计,但是必须用QueryWrapper的方式来实现。
void test2(){
//方式二:lambda格式按条件查寻
QueryWrapper<Student> qw = new QueryWrapper();
//as count(别名)
qw.select("count(*) as count,cid");
//查询cid相同的数据
qw.groupBy("cid");
//此处选择Map集合来存储,因为之前使用的list集合是一个Student实体类类型,count参数传不进去,就会返回空值
List<Map<String, Object>> list = studentDao.selectMaps(qw);
System.out.println(list);
}
1.3查询条件设置
1.登录
简单的写一个登录的条件,eq就相当于equals。如果我们给的条件在数据库中查不到,就会返回null,登陆失败,反之登录成功。
@Test
void test5(){
LambdaQueryWrapper<Student> lqw = new LambdaQueryWrapper<>();
//条件:一个登录的方法
lqw.eq(Student::getName,"克莱").eq(Student::getAge,11);
//只查询一条数据
Student loginStu = studentDao.selectOne(lqw);
System.out.println(loginStu);
}
2.范围查询
@Test
void test5(){
LambdaQueryWrapper<Student> lqw = new LambdaQueryWrapper<>(){
//使用此方法时要注意范围要先写小的后写大的
lqw.between(Student::getAge,10,30);
List<Student> list = studentDao.selectList(lqw);
System.out.println(list);
}
3.模糊匹配
//模糊匹配
@Test
void test6(){
LambdaQueryWrapper<Student> lqw = new LambdaQueryWrapper<>();
lqw.like(Student::getName,"克");
List<Student> list = studentDao.selectList(lqw);
System.out.println(list);
}
条件有许多种,这里我只列举三种比较常用的条件,具体的请到官网进行查看。
1.4字段映射与表名映射
在我们开发过程中,如果你的实体类属性名与数据库中的字段列表名不同,但是又不想大费周章的更改,我们就可以使用**@TableField**注解,进行修改,简单便捷。
@TableField(value = "username")
private String name;
我们还可以利用**@TableField**注解来设置一些字段是否在数据库表中存在,默认为true,即为存在,false则为不存在。
@TableField(exist = false)
private int abc;
可以用**@TableField来设置哪些字段不参与一些sql语句查询,其原理大致与exist**相同。
@TableField(select = false)
private int abc;
1.5DML编程控制
1.1id生成策略控制
在我们进行对数据库添加表操作时,id会有不同的生成策略,可以主键自增,也可以自定义它自增的方式。、
- AUTO:使用数据库id自增策略控制id生成
- NONE:不设置id生成策略
- INPUT:用户手动输入id
- ASSIGN_ID:雪花算法生成id(可兼容数值型和字符串型),雪花算法大概意思就是随机生成一个long类型的数。
- ASSIGN_UUID:以UUID生成算法作为id生成策略。
用法:在实体类id这个属性上使用@TableId
@TableId(type = IdType.AUTO)
private int id;
简化
在现实中,我们一个项目大概要许多给实体类,如果我们控制id生成策略,就可以在配置文件中进行配置,以免去在每个实体类中都要完成相同且重复的操作。配置完成,这个id生成策略就可以在所有类中生效。
application.yaml配置:
spring:
datasource:
username: root
password:
url: jdbc:mysql://localhost:3306/dbs?&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#开启MyBatisPlus的日志(输出到控制台)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: assign_id
1.2删除操作(多条数据同时删除)
//多条数据删除
@Test
void delete(){
//根据id进行多条数据删除
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
studentDao.deleteBatchIds(list);
}
1.3乐观锁
乐观锁使用来解决并发问题得,在我们得生活中使用购物软件时,会遇到一些限量商品,当商品销售到只剩下一个的时候,就可能有多个人来购买这一个商品,如果没有锁的作用,就可能出现负数的商品,为了避免这一情况的发生,锁就显得非常重要了。
程序讲解
-
首先要在数据库表中加入一个version字段默认值为1,每当我们执行修改语句时version就会
+1。 -
在实体类中声明属性,并且加上注解。
@Version private int version;
-
在Config中加入乐观锁的拦截器,实现锁机制对应的动态sql语句拼装。
//乐观锁拦截器 mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
-
在测试代码中进行测试
@Test void test10(){ Student student = studentDao.selectById(6);//version=2 Student student1 = studentDao.selectById(6);//version=2 student1.setName("尼古拉斯"); studentDao.updateById(student1); //version=>3 student.setName("克拉克斯顿"); //此时version=2是否还成立已经不成立了 studentDao.updateById(student); }
当student1执行之后version=3,当student执行之时,version已经=3,就不再满足条件了,所以student就会失效。