02、MyBatisPuls
一、MyBatisPuls
1、myBatisPuls介绍
MyBatisPlus(MP) 是基于MyBatis框架基础上开发的增强工具,旨在简化开发,提高效率。
2、myBatisPlus特性
1、无入侵:只做增强不做改变,不会对现有工程产生影响。
2、强大的CRUD操作: 内置通用Mapper,扫两配置即可实现单表CRUD操作
3、支持主键自动生成
4、内置分页插件
3、springboot 整合mybatisplus要加入下面的依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
二、标准数据层开发
一、标准数据层CRUP功能
dao层
/**
* dao要求:
* 1. 继承BaseMapper,并且要写上泛型[这是dao操作那张表,就写那张表对应的javaBean类型]
* 2. 在接口上大注解@Mapper或者在启动类上打注解@MapperScan("com.cwl.dao")
*/
@Mapper
public interface UserDao extends BaseMapper<User> {
}
配置文件application.yml中设置jdbc参数
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///user_surface
username: root
password: root
配置文件application.yml中设置sql语句打印日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1、新增
@SpringBootTest
public class TestInsert {
@Autowired
private UserDao userDao;
@Test
public void Insert(){
User user = new User();
user.setName("zhsc");
user.setAge(19);
user.setPassword("1234556");
user.setTel("1234567");
int row = userDao.insert(user);
System.out.println("row = " + row);
}
}
2、删除
// 按照id地址删除
@SpringBootTest
public class TestDelete {
@Autowired
private UserDao userDao;
@Test
public void test(){
int row = userDao.deleteById(2);
System.out.println("row = " + row);
}
}
3、修改
@SpringBootTest
public class TestUpdate {
@Autowired
private UserDao userDao;
@Test
public void test(){
//1.先查询
User user = userDao.selectById(1);
user.setTel("1234567890");
//2.后修改
int row = userDao.updateById(user);
System.out.println("row = " + row);
}
}
4、根据id查询
@SpringBootTest
public class TestFind {
@Autowired
private UserDao userDao;
@Test
public void test(){
//1. 按id去查
User user = userDao.selectById(1);
System.out.println("user = " + user);
}
}
二、分页功能
1、分页查询
设置分页拦截器作为spring管理的bean
@Configuration
public class MyBatisPlusConfig {
//配置分页拦截器
@Bean
public MybatisPlusInterceptor mip(){
//1. 构建mybatisplus的拦截器对象
MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
//2. 把分页拦截器设置到mip里面
mpi.addInnerInterceptor(new PaginationInnerInterceptor());
return mpi;
}
}
@SpringBootTest
public class testFindPage {
@Autowired
private UserDao userDao;
@Test
public void test(){
//1. 创建page对象 用来包装,查询第几页 每页查询多少条
Page<User> page = new Page<>(2,2);
//2. 执行分页查询
// 参数一 page对象
// 参数二 查询条件,如果是面对整张表的分页,那么就写null
userDao.selectPage(page, null);
System.out.println("当前页 = " + page.getCurrent());
System.out.println("总页数 = " + page.getPages());
System.out.println("每页个数 = " + page.getSize());
System.out.println("总记录数 = " + page.getTotal());
System.out.println("当前页的集合 = " + page.getRecords());
}
}
三、DQL控制
一、条件查询方式
1、条件查询的普通写法
@SpringBootTest
public class TestFind {
@Autowired
private UserDao userDao;
@Test
public void test(){
//查询年龄大于等于18岁,小于65岁的用户
//1. 构造条件对象
QueryWrapper<User> qu = new QueryWrapper<>();
//2. 设置条件 select * from user where age>=18 and age<65
qu.ge("age", 18).lt("age",65);
//3. 执行查询
List<User> list = userDao.selectList(qu);
System.out.println("list = " + list);
}
}
2、条件查询的lambda的写法
@SpringBootTest
public class TestLambdaFind {
@Autowired
private UserDao userDao;
@Test
public void test(){
//1. 创建LambdaQueryWrapper
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//2. 设置条件
lqw.ge(User::getAge, 18).lt(User::getAge, 55);
//3. 执行查询
List<User> list = userDao.selectList(lqw);
System.out.println("list = " + list);
}
}
3、组合条件查询
@SpringBootTest
public class testAndOr {
@Autowired
private UserDao userDao;
// 组合条件的写法:默认多个条件一起写,就会使用and关键字来拼接
// 如果希望使用or关键字,那么需要在条件中间调用or()来衔接
@Test
public void test(){
//1. 构建条件对象
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//2. 设置条件
lqw.le(User::getAge, 30).or().gt(User::getAge, 18);
//3. 执行查询
List<User> list = userDao.selectList(lqw);
System.out.println("list = " + list);
}
}
4、动态条件查询
@SpringBootTest
public class TestDynamic {
// 动态条件的设置 条件不一定有,需要经过判定之后,才能追加条件
@Autowired
private UserDao userDao;
@Test
public void test(){
//1. 准备一份数据
User user = new User();
user.setName("admin");
user.setAge(17);
user.setPassword("12345");
//2. 判断条件,然后追加条件
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//2.1 设置条件 都使用第一个参数位置来控制条件是否追加, true 就追加, false , 就不追加条件
lqw.eq(user.getName() != null, User::getName, user.getName());
lqw.eq(user.getAge() != null, User::getAge, user.getAge());
lqw.eq(user.getPassword() != null, User::getPassword, user.getPassword());
//3. 执行查询
List<User> list = userDao.selectList(lqw);
System.out.println("list = " + list);
}
}
二、查询条件设置
1、统计查询
//统计查询
@Test
public void test(){
QueryWrapper<User> qw = new QueryWrapper<>();
//设置查询的列
qw.select("count(*) as number", "gender"); //select count(*), gender from user
//设置分组
qw.groupBy("gender"); //select count(*), gender from user group by gender
List<Map<String, Object>> list = userDao.selectMaps(qw);
System.out.println("list = " + list);
}
2、等价查询,只查询一条记录
// 等价查询,只查询一条记录
@Test
public void test(){
//1. 创建条件对象
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//1.1 设置条件
lqw.eq(User::getName , "admin").eq(User::getPassword , "123");
//2. 执行查询
User user = userDao.selectOne(lqw);
System.out.println("user = " + user);
}
3、区间查询
// 区间查询
@Test
public void testFindByCondition09(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//查询年龄在18 和 65 之间的用户。
lqw.between(User::getAge , 18 , 65);
List<User> list = userDao.selectList(lqw);
System.out.println("list = " + list);
}
4、模糊查询
// 模糊查询
@Test
public void test(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//1. 设置条件 %a%
lqw.like(User::getName , "a");
//排序 : 使用年龄来排序,降序排序
lqw.orderByDesc(User::getAge);
List<User> list = userDao.selectList(lqw);
System.out.println("list = " + list);
}
5、查询条件:更多查询条件设置参看
https://baomidou.com/pages/10c804/#abstractwrapper
四、字段映射与表名映射
1、表字段与编码属性设计不同步(属性名与列名不匹配)
/*
1. mybatisplus 查询的时候,默认是查询所有的列,并且不是使用 select * 的方式来查询
而是使用select 每一列的方式来查询。
2. mybatisplus 查询的时候,是通过扫描了JavaBean里面的所有属性,把所有的属性名
当成是列名来查询。
select id , name , password , age , tel from user
3. 如果某个属性的名字和列名对不上那么就会报错!
Unknown column 'password' in 'field list'
4. 解决方案:
在属性上加上注解 @TableField,给value属性设值,值就是列的名字,设置了之后,mybtisplus
就按照这个名字来查询
select id , name , pwd as password, age , tel from user
*/
@TableField("pwd") //设置列的名字
private String password;
2、编码中添加了数据库中未定义的属性(处理不存在的属性)
/*
1. 这个属性是我们为了在其他地方方便判断用户的信息,设置的一个属性。
2. 这个属性并没有任何一个列与之对应
3. 为了告诉mybatisplus 查询的时候,不要把这个属性计算在内。
4. 需要设置注解,exist = false, 没有任何一个列与之对应!
*/
@TableField(exist = false)
private String online;
3、采用默认查询开放了更多的字段查看权限(屏蔽某些字段不查询)
//如果不希望把这个列查询出来,那么就可以加上注解@TableField(select=false)
@TableField(select = false)
private String gender;
4、表名与编码开发设计不同步(表名与类型映射)
/*
mybatisplus 操作表的策略:
1. mybatisplus 查询表的时候,它都是扫描JavaBean里面的所有属性名,然后当成是列名来操作
2. 至于具体操作哪张表,其实它是把JavaBean的名字,变成全小写之后去匹配!
User -----> user表
3. 至于到底找的是哪个JavaBean,从dao的类的定义泛型位置出发的。
public interface UserDao extends BaseMapper<User> {
Table 'user_surface.user' doesn't exist
Table 'user_surface.aa' doesn't exist
4. 在类上加上注解@TableName("t_user"), 设置value属性值,它会被当成是表名来看待!
*/
4.1 在JavaBean的类上直接打上注解
@TableName("t_user")
@Data
public class User {}
4.2 可以使用全局设置(在application.yml文件中)
mybatis-plus:
global-config: # 全局配置
db-config: # 配置表的前缀 和 id的策略
table-prefix: t_
id-type: auto
四、DML
一、id自增策略控制(Insert)
/*
ID 的策略:
AUTO: 使用数据库自增的id
NONE: 没有设置策略,约等于 INPUT
INPUT : 使用用户输入的id,如果没有输入就默认使用雪花算法生成的id
ASSIGN_ID : 使用雪花算法生成的id
ASSIGN_UUID : 使用UUID生成的id,但是它得到的是一个字符串!
*/
@TableId(type = IdType.ASSIGN_UUID)
private Long id;
二、全局设置
mybatis-plus:
global-config: # 全局配置
db-config: # 配置表的前缀 和 id的策略
table-prefix: t_
id-type: auto
三、批量查询–多记录操作(Select)
//批量查询
@Test
public void testSelectBatch(){
//构建集合,装id值
List<Long> ids = Arrays.asList(1579722941208236033L, 1579722996866727938L);
//执行查询
List<User> list = userDao.selectBatchIds(ids);
System.out.println("list = " + list);
}
四、批量删除—多记录操作(Delete)
//批量删除
@Test
public void testDeleteBatch(){
//构建集合,装id值
List<Long> ids = Arrays.asList(1579722941208236033L, 1579722996866727938L);
//执行查询
int row = userDao.deleteBatchIds(ids);
System.out.println("row = " + row);
}
五、逻辑删除—逻辑删除(Delete/Update)
1、删除操作业务问题:业务数据从数据库中丢弃
2、逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
1、在属性上打上注解
//表示这个是逻辑删除字段。 也可以使用全局来设置。
// 1 即表示删除的值 , 0 表示未删除的值
@TableLogic(delval = "1" , value = "0")
private int deleted;
2、可以使用全局设置(在application.yml文件中)
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除的字段名
logic-delete-value: 1 # 删除的值
logic-not-delete-value: 0 # 未删除的值
//逻辑删除
@Test
public void testDelete(){
userDao.deleteById(1579723562409803777L);
}
//查询所有
@Test
public void testFindAll(){
System.out.println("list = " + userDao.selectList(null));
}
六、乐观锁(Update)
1、实体类中添加对应字段,并设定当前字段为乐观锁版本控制字段
// 乐观锁的字段
@Version
private int version;
2、配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mpi (){
MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
// 添加乐观锁的拦截器
mpi.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mpi;
}
}
3、使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行
//乐观锁
@Test
public void testUpdate(){
//1. 先查询
User user = userDao.selectById(1L);
//再查一次!
User user02 = userDao.selectById(1L);
//2. 改密码:
user.setPassword("888");
//3. 执行更新
int row = userDao.updateById(user);
System.out.println("row = " + row);
// 再改
user02.setPassword("999");
int row02 = userDao.updateById(user02);
System.out.println("row02 = " + row02);
}
最后更新的结果是 888
五、快速开发
1、代码生成器
@SpringBootTest
public class TestCode {
@Test
public void test01(){
//创建代码生成器对象,执行生成代码操作
AutoGenerator autoGenerator = new AutoGenerator();
//2. 数据源相关配置:读取数据库中的信息,根据数据库表结构生成代码
DataSourceConfig dataSource = new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/book?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("root");
autoGenerator.setDataSource(dataSource);
//设置全局配置
GlobalConfig globalConfig = new GlobalConfig();
//设置代码生成位置
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
//设置生成完毕后是否打开生成代码所在的目录
globalConfig.setOpen(false);
//设置作者
globalConfig.setAuthor("cwl");
//设置是否覆盖原始生成的文件
globalConfig.setFileOverride(true);
//设置数据层接口名,%s为占位符,指代模块名称
globalConfig.setMapperName("%sDao");
//设置Id生成策略
globalConfig.setIdType(IdType.ASSIGN_ID);
autoGenerator.setGlobalConfig(globalConfig);
//设置包名相关配置
PackageConfig packageInfo = new PackageConfig();
//设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
packageInfo.setParent("com.cwl");
//设置实体类包名
packageInfo.setEntity("bean");
//设置数据层包名
packageInfo.setMapper("dao");
autoGenerator.setPackageInfo(packageInfo);
//策略设置
StrategyConfig strategyConfig = new StrategyConfig();
//设置当前参与生成的表名,参数为可变参数
strategyConfig.setInclude("t_user");
//设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名 例如: User = tbl_user - tbl_
strategyConfig.setTablePrefix("t_");
//设置是否启用Rest风格
strategyConfig.setRestControllerStyle(true);
//设置乐观锁字段名
strategyConfig.setVersionFieldName("version");
//设置逻辑删除字段名
strategyConfig.setLogicDeleteFieldName("deleted");
//设置是否启用lombok
strategyConfig.setEntityLombokModel(true);
autoGenerator.setStrategy(strategyConfig);
//执行方法生成代码
autoGenerator.execute();
}
}