一.Mybatis_plus学习记录
1)准备SQL语句
DROP TABLE IF EXISTS USER;
CREATE TABLE USER
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO USER (id, NAME, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
2)建立好Springboot工程,写好连接配置 创建实体类User,UserMapper
配置application.properties
#数据库连接(我的数据库版本)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@Autowiredprivate
UserMapper userMapper;//查询User表中所有的Mapper
@Test
void findall() {
List<User> userList =userMapper.selectList(null); System.out.println(userList);
}
//添加(mp自带主键生成策略 雪花算法实现具体怎么实现不清楚)
@Test
void addUser() {
User user = new User();
user.setName("BBH");
user.setAge(28);
user.setEmail("26629@qq.com");
int rows = userMapper.insert(user);
System.out.println(rows);
}
//修改
@Test
void updateUser() {
User user = new User();
user.setId(22L);
user.setName("LUCKY");
user.setAge(28);
user.setEmail("26629@qq.com");
int rows = userMapper.updateById(user); System.out.println(rows);}
3)自动填充功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VgzIqYdk-1604493615581)(E:\Typora\MyTypora\尚硅谷在线教育系统.assets\1604368656375.png)]
1.数据库加入创建时间和跟新时间2个属性
2.实体类加上注解
//自动填充
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
3.配置MyMetaObjectHandler 实现MetaObjectHandler接口
@Component//加入到Spring容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
4)乐观锁
**主要适用场景:**当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
@Version
@TableField(fill = FieldFill.INSERT_UPDATE) //不必要 只是为了能够更清楚的看乐观锁的效果
private Integer version;
@Configuration //代表Spring的配置类
@MapperScan("com.atguigu.mpdemo1102.mapper")
public class MpConfig {
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
//测试乐观锁
@Test
void testOptimisticLocker() {
//根据id查询
User user = userMapper.selectById(1323462293551366145L);
//修改
user.setAge(200);
userMapper.updateById(user);
}
5)批量查询
//测试查询多条语句
@Test
void testmanysearch(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
@Test
public void testSelectByMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
6)分页
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
(1)创建配置类
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
(2) 编写分页代码
直接new page对象,传入两个参数:当前页和每页记录数
调用mp方法实现分页查询
//测试分页插件
@Test
void testSelectPage(){
//1.创建page对象
//2.传入两个参数:当前页和每页记录数
Page<User> page = new Page<>(1,3);
//调用mp分页查询的方法
userMapper.selectPage(page,null);
//通过Page对象获取分页数据
System.out.println("当前页"+page.getCurrent());//当前页
System.out.println("List<>集合"+page.getRecords());//每页的List<>集合
System.out.println("每页显示记录数"+page.getSize());//每页显示记录数
System.out.println("总记录数"+page.getTotal()); //总记录数
System.out.println("总页数"+page.getPages()); //总页数
System.out.println(page.hasNext());//是否有下一页
System.out.println(page.hasPrevious()); //是否有上一页
}
7)删除
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
//测试删除
@Test
void testDelete(){
int rows = userMapper.deleteById("22L");
System.out.println(rows);
}
//批量删除
@Test
void testDeleteBatchIds(){
int result = userMapper.deleteBatchIds(Arrays.asList(3,4,5));
System.out.println(result);
}
//简单的条件查询删除
@Test
void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
int result = userMapper.deleteByMap(map);
System.out.println(result);
}
- 逻辑删除:
(1)数据库中添加 deleted字段
ALTER TABLE `user` ADD COLUMN `deleted` boolean
(2)实体类添加deleted 字段
并加上 @TableLogic 注解 和 @TableField(fill = FieldFill.INSERT) 注解
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
(3)元对象处理器接口添加deleted的insert默认值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jDHtK7zP-1604493615586)(E:\Typora\MyTypora\尚硅谷在线教育系统.assets\1604399578140.png)]
(4)application.properties 加入配置
此为默认值,如果你的默认值和mp默认的一样,该配置可无
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
(5)在 MybatisPlusConfig 中注册 Bean
/**
*逻辑删除
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
(6)测试逻辑删除
- 测试后发现,数据并没有被删除,deleted字段的值由0变成了1
- 测试后分析打印的sql语句,是一条update
- **注意:**被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
8)性能分析
性能分析拦截器,用于输出每条 SQL 语句及其执行时间
SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题
配置插件
(1)参数说明
参数:maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题。
参数:format: SQL是否格式化,默认false。
(2)在 MybatisPlusConfig 中配置
/**
* SQL 执行性能分析插件
* 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
* @return
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(500);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
9)MybatisPlus条件构造器
wapper介绍
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xnK9X3Qx-1604493615593)(E:\Typora\MyTypora\尚硅谷在线教育系统.assets\27b56b5e-39a6-42ba-b7ed-4f109b6ad7bf.png)]
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : Entity 对象封装操作类,不是用lambda语法
UpdateWrapper : Update 条件封装,用于Entity对象更新操作
AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
1、ge、gt、le、lt、isNull、isNotNull
2、eq、ne**
3、between、notBetween**
4、allEq
5、like、notLike、likeLeft、likeRight
6、in、notIn、inSql、notinSql、exists、notExists**
in、notIn:
notIn("age",{1,2,3})--->age not in (1,2,3)notIn("age", 1, 2, 3)--->age not in (1,2,3)
inSql、notinSql:可以实现子查询
- 例:
inSql("age", "1,2,3,4,5,6")
—>age in (1,2,3,4,5,6)
- 例:
inSql("id", "select id from table where id < 3")
—>id in (select id from table where id < 3)
7、or、and**
**注意:**这里使用的是 UpdateWrapper
不调用or
则默认为使用 and
连
9、orderBy、orderByDesc、orderByAsc
10、last
直接拼接到 sql 的最后
**注意:**只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用
//MybatisPlus条件构造器
@Test
void test01(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
// wrapper.ge("age",30);//年龄大于等于30
// wrapper.isNotNull("version");//不为空
//wrapper.eq("age",20);//eq等于
//wrapper.notBetween("age",18,20);不包含
Map<String, Object> map = new HashMap<>();
map.put("id", 2);
map.put("name", "Jack");
map.put("age", 20);
//wrapper.allEq(map);
//wrapper.notLike("name", "e").likeRight("email", "t");
//SELECT id,name,age,email,create_time,update_time,version,eleted FROM WHERE
// AND name NOT LIKE '%e%' AND email LIKE 't%'
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}