MyBatisPlus
- 在真实开发中 在表的字段中还会存在:
- version(乐观锁),deleted(逻辑删除),created和updated(时间);
快速入门
创建一个springboot项目
-
导入依赖:
-
<!-- 数据库驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- mybatis-plus自己开发的 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency>
连接数据库
关于主键id :ID_WORKER //默认的全局唯一id(雪花算法)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t9TSVbBT-1644408533648)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215221812729.png)]
-
@TableId(type = IdType.AUTO) //对应数据库中的id也要自增; IdType.NONE //未设置主键 IdType.INPUT //手动输入 UUID //全局唯一id UUID ID_WORKER //默认的全局唯一id ID_WORKER_str//ID_WORKER字符串表示法
数据据操作
核心: -在mapper层继承父接口baseMapper,然后调用父接口中的方法实现CRUD;
泛型一定要写,是表对应的pojo对象;
-
public interface UserMapper extends BaseMapper<User>
新增
-
@Test void test1(){ //测试插入数据 User user=new User(); user.setUsername("lang").setAge(18).setEmail("222@qq.com"); userMapper.insert(user); }
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mlVGNKtx-1644408533652)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215222838204.png)]
更新
- 通过条件自动拼接动态sql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZahFBvul-1644408533653)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215222938006.png)]
-
@Test void test2(){ User user=new User(); user.setId(5L);//id=5 user.setUsername("王祖贤"); //注意需要传入的是对象; userMapper.updateById(user); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bbiKBVQN-1644408533653)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215223529148.png)]
补充:自动填充
-
创建时间 修改时间:让它们自动的生成填充 而不是手动添加;
-
一:在表中创建对应的字段
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hPz3Cwqm-1644408533654)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215224337484.png)]
-
二:添加注解
-
//创建时更新 @TableField(fill = FieldFill.INSERT) private Date created; //创建和更改时更新 @TableField(fill = FieldFill.INSERT_UPDATE) private Date updated;
-
三 编写处理器
-
实现MetaObjectHandler接口;
-
@Component @Slf4j //添加日志注解 public class ObjectHandler implements MetaObjectHandler { //插入时的填充策略; @Override public void insertFill(MetaObject metaObject) { log.info("开始执行插入填充.."); this.setFieldValByName("created", new Date(), metaObject); this.setFieldValByName("updated", new Date(), metaObject); } //更新时的填充策略; @Override public void updateFill(MetaObject metaObject) { log.info("开始执行更新填充.."); this.setFieldValByName("updated", new Date(), metaObject); } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jpeQaoMQ-1644408533654)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215230145595.png)]
乐观锁
- 乐观锁:顾名思义,比较乐观,它总是认为不会出现问题,无论什么操作都不去上锁,如果出现问题,再次更新值进行测试:version
- 乐观锁适用于写比较少的情况下(多读场景)
- 悲观锁:十分悲观,认为什么操作都可能出现问题,无论干什么都会上锁,再去操作;
- 一般多写的场景下用悲观锁就比较合适
-
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式: -
<取出记录时,获取当前 version 更新时,带上这个 version 执行更新时, set version = newVersion where version = oldVersion 如果 version 不对,就更新失败
举例
-
乐观锁:1.先查询,获得版本号 2.更新时 同时要把版本号进行更新,一般加1 --A update user set name="li",version=version+1 where id=2 and version=1 --B 如果B线程抢先完成,此时version=2,会导致A线程修改失败; update user set name="li",version=version+1 where id=2 and version=1
测试
-
1.在表中增加字段;
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XtWbL6Rb-1644408533655)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215232036691.png)]
-
2.同步实体类,增加注解
-
@Version //代表乐观锁; private Integer version;
-
3.注册乐观锁插件
-
@Configuration //标记配置类 @EnableTransactionManagement //管理事务,默认开启 @MapperScan("com.jt.mapper") public class MyBatisPlusConfig { //注册乐观锁插件 官方文档 版本3.4.3 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }
-
4.测试乐观锁
-
@Test void test3(){ //测试乐观锁成功 //单线程情况 更改数据信息 //1.查询用户信息 User user = userMapper.selectById(2); //2.修改用户信息 user.setUsername("刘亦菲").setEmail("899@qq.com"); //3.执行更新 userMapper.updateById(user); }
-
输出结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5GmvRfU-1644408533655)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215234103756.png)]
-
测试乐观锁失败的案例
-
@Test void test4(){ //测试乐观锁执行失败 //1.线程A执行操作数据 User user = userMapper.selectById(3); user.setUsername("刘亦菲").setEmail("899@qq.com"); //2.线程A还未执行完,线程B插队执行; User user2 = userMapper.selectById(3); user2.setUsername("刘诗诗").setEmail("999@qq.com"); userMapper.updateById(user2); //线程A未执行 更新; userMapper.updateById(user); }
结果分析
- 2次查询更改都是通过version=2去进行操作,但是线程B操作完之后,version的值已经变成3
- 所以线程A的操作就会失效;
- 如果没有乐观锁那么线程B的值就会被覆盖;
- 多线程下一定要加锁;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T0EdtL3j-1644408533655)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215235236027.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vtmYeu9C-1644408533656)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211215235631045.png)]
测试2
-
需求:查询id=1,2,3的用户信息;
-
@Test void test5(){ //参数是集合,所以需要通过asList将数组转换为集合; List<User> list = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); //将结果遍历输出; list.forEach(System.out::println); }
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IBdqYi2u-1644408533656)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211217201150557.png)]
-
查询姓名为刘亦菲,年龄为20的用户信息;
-
@Test void test6(){ Map map=new HashMap(); map.put("username", "刘亦菲"); map.put("age", 20); List users = userMapper.selectByMap(map); users.forEach(System.out::println); }
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AK2senl3-1644408533657)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211217203030114.png)]
分页查询
导入插件
-
//配置分页插件; @Bean public MybatisPlusInterceptor mybatisPlusInterceptor2() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; }
-
@Test void test7(){ //1.设置当前页,和每页用户数; Page<User> page=new Page<>(2,5); userMapper.selectPage(page, null); //打印记录; page.getRecords().forEach(System.out::println); //获取总用户数; System.out.println(page.getTotal()); }
删除
-
@Test void test9(){ Map map=new HashMap(); map.put("id", "1471119629576306691"); map.put("age","18"); userMapper.deleteByMap(map); }
逻辑删除
- 物理删除:从数据库中直接删除
- 逻辑删除:在数据库中没有删除,而是通过一个变量使其失效;
- 管理员可以查看被删除的记录
- 防止数据的丢失,类似于回收站;
- 1在表中增加字段
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tbIARZrg-1644408533657)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211217212144659.png)]
-
2在pojo对象增加属性
-
//逻辑删除注解 @TableLogic private Integer deleted;
-
3配置插件
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤 2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
-
@Test void test01(){ userMapper.deleteById("1471119629576306690"); }
-
测试结果:实际上是走的更新操作;
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UMzxRyHV-1644408533658)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211217213450753.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwMGoasa-1644408533659)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211217213536528.png)]
- 注意:虽然数据在数据库中但是并不能进行操作;比如查询,更改;
条件构造器
-
用于复杂条件下的查询,书写复杂的sql语句;
-
测试一:
-
@Test void test1(){ //测试1:查询姓名不为null,邮箱不为null,年龄大于18的用户 QueryWrapper<User> queryWrapper=new QueryWrapper<User>(); queryWrapper.isNotNull("username") .isNotNull("email"). gt("age", 18); userMapper.selectList(queryWrapper).forEach(System.out::println); }
-
测试二
-
@Test void test2(){ //测试二 查询年龄在20岁到30岁之间的用户数 QueryWrapper<User> queryWrapper=new QueryWrapper<>(); queryWrapper.between("age", 20, 30); Integer integer = userMapper.selectCount(queryWrapper); System.out.println(integer); }
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9m8JRs63-1644408533660)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20211217223002104.png)]
-
测试三
-
@Test void test3(){ //本类测试模糊查询 QueryWrapper<User> queryWrapper=new QueryWrapper<>(); queryWrapper.notLike("username", "刘") .likeRight("email", "2"); List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper); maps.forEach(System.out::println); }
}
- [外链图片转存中...(img-9m8JRs63-1644408533660)]
- 测试三
- ```java
@Test
void test3(){
//本类测试模糊查询
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.notLike("username", "刘")
.likeRight("email", "2");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}