七,MyBatis-Plus 扩展功能:乐观锁,代码生成器,执行SQL分析打印(实操详 ...

打印 上一主题 下一主题

主题 882|帖子 882|积分 2646

七,MyBatis-Plus 扩展功能:乐观锁,代码生成器,执行SQL分析打印(实操详细利用)

@
目录

1. 乐观锁

首先我们需要先相识开发中的一个常见场景,叫做并发请求。
并发请求就是在同一时刻有多个请求,同时请求服务器资源,如果是获取信息,没什么题目,但是如果是对于信息做修改操作,那就会出现题目。
这里我们举一个例子。比如:目前商品的库存只剩余 1件了,这个时候有多个用户都想要购买这件商品,都发起了购买商品的请求,那么能让这多个用户都购买到么,肯定是不可的,因为多个用户都买到了这件商品,那么就会出现超卖题目,库存不敷时没法发货的。所以在开发中就要解决这种超卖的题目。

抛开超卖的这一种场景,诸云云类并发访问的场景非常多,这类场景的核心题目就是,一个请求在执行的过程中,其他请求不能改变数据,如果是一次完整的请求,在该请求的过程中其他请求没有对于这个数据产生修改操作,那么这个请求时能够正常修改数据的。如果该请求在改变数据的过程中,已经有其他请求改变了数据,那该请求就不去改变这条数据了。

想要解决这类题目,最常见的就是加锁的头脑,锁可以用验证在请求的执行过程中,是否有数据发生改变。
常见的数据库锁类型有两种,灰心锁和乐观锁。
一次完成的修改操作是:先查询数据,然后修改数据。
如许做的操作能够保证读取到的信息就是当前的信息,保证了信息的正确性,但是并发效率很低,在现实开发中利用灰心锁的场景很少,因为在并发时,我们是要保证效率的。
乐观锁: 乐观锁是通过表字段完成设计的,他的核心头脑是,在读取的时候不加锁,其他请求依然可以读取到这个数据,在修改的时候判断一个数据是否有被修改过,如果有被修改过,那本次请求的修改操作失败。
详细的通过 SQL 是如许实现的,添加了一个 where version = 1
如许做的操作是不会对于数据读取产生影响,并发的效率较高,但是可能目前看到的数据并不是真实信息数据,是被修改之前的,但是在很多场景下是可以容忍的,并不是产生很大影响。例如:很多时候我们看到的是有库存,或者都加入都购物车,但是点进去以后库存没有了。
在数据库表中添加一个字段 version,表示版本,默认值是1

生成后的结果

找到实体类,添加对应的属性,并利用 @Version标注 为这是一个乐观锁字段信息。

因为要对每条修改语句完成语句的增强,这里我们通过拦截器的设置,让每条修改的 sql 语句在执行的时候,都加上版本控制的功能。
  1. import com.baomidou.mybatisplus.annotation.DbType;
  2. import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
  3. import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
  4. import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
  5. import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
  6. import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
  7. import org.apache.ibatis.plugin.Interceptor;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. @Configuration
  11. public class MybatisPlusConfig {
  12.     @Bean
  13.     public MybatisPlusInterceptor mybatisPlusInterceptor() {
  14.         MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
  15.         /*
  16.         通过配置类来指定一个具体数据库的分页插件,因为不同的数据库的方言不同,具
  17.         体涩会给你从的分页语句也会不同,这里我们指定数据库为 MySQL数据库
  18.          */
  19.         mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  20.         mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁
  21.         return mybatisPlusInterceptor;
  22.     }
  23. }
复制代码
测试结果,这里我们模拟先查询,再修改
  1. @Test
  2. void updateTest(){
  3.     User user = userMapper.selectById(6L);
  4.     user.setName("li");
  5.     userMapper.updateById(user);
  6. }
复制代码

我们通过检察拼接好的SQL语句发现,查询时将User的数据查询出来,是包罗version版本信息的

当我们完成修改时,他会将版本号 + 1
此时检察数据发现,更改姓名后,version已经为2了

接下来我们模拟一下,当出现多个修改请求的时候,是否能够做到乐观锁的结果。
乐观锁的结果是,一个请求在修改的过程中,是允许另一个请求查询的,但是修改时会通过版本号是否改变来决定是否修改,如果版本号变了,证明已经有请求修改过数据了,那这次修改不生效,如果版本号没有发生变化,那就完成修改。
  1. package com.rainbowsea;
  2. import com.rainbowsea.bean.User;
  3. import com.rainbowsea.mapper.UserMapper;
  4. import org.junit.jupiter.api.Test;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. @SpringBootTest
  8. public class LockTest {
  9.     @Autowired
  10.     private UserMapper userMapper;
  11.     @Test
  12.     void updateTest2() {
  13.         // 模拟操作1的查询操作
  14.         User user1 = userMapper.selectById("5");
  15.         System.out.println("查询结果:" + user1);
  16.         // 模拟操作2的查询操作
  17.         User user2 = userMapper.selectById("5");
  18.         System.out.println("查询结果:" + user2);
  19.         // 模拟操作2的修改操作
  20.         user2.setName("liHua");
  21.         userMapper.updateById(user2);
  22.         // 模拟操作1的修改操作
  23.         user1.setName("zhangsan");
  24.         userMapper.updateById(user1);
  25.     }
  26. }
复制代码
我们来看下这段代码的执行过程,这段代码其实是两次操作,只不过操作1在执行的过程中,有操作2完成了对于数据的修改,这时操作1就无法再次举行修改了
操作1的查询:此时版本为2

操作2的查询:此时版本为2

操作2的修改:此时检查版本,版本没有变化,所以完成修改,并将版本改为3


操作1的修改:此时检查版本,版本已经有最初获取的版本信息发生了变化,所以杜绝修改

2. 代码生成器

代码生成器和逆向工程的区别在于,代码生成器可以生成更多的结构,更多的内容,允许我们能够设置生成的选项更多。在这里我们演示一下代码生成器的用法。
参考官网,利用代码生成器需要引入两个依赖;
  1.   
  2.         
  3.         <dependency>
  4.             <groupId>com.baomidou</groupId>
  5.             <artifactId>mybatis-plus-boot-starter</artifactId>
  6.             <version>3.5.3</version>
  7.         </dependency>
  8.         
  9.         <dependency>
  10.             <groupId>org.freemarker</groupId>
  11.             <artifactId>freemarker</artifactId>
  12.             <version>2.3.31</version>
  13.         </dependency>
复制代码
编写代码生成器代码
  1. @SpringBootTest
  2. class GeneratorApplicationTests {
  3.     public static void main(String[] args) {
  4.         FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false", "root", "root")
  5.                 .globalConfig(builder -> {
  6.                     builder.author("powernode") // 设置作者
  7.                             //.enableSwagger() // 开启 swagger 模式
  8.                             .fileOverride() // 覆盖已生成文件
  9.                             .outputDir("D://"); // 指定输出目录
  10.                 })
  11.                 .packageConfig(builder -> {
  12.                     builder.parent("com.powernode") // 设置父包名
  13.                             .moduleName("mybatisplus") // 设置父包模块名
  14.                             .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
  15.                 })
  16.                 .strategyConfig(builder -> {
  17.                     builder.addInclude("powershop_user") // 设置需要生成的表名
  18.                             .addTablePrefix("powershop"); // 设置过滤表前缀
  19.                 })
  20.                 .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
  21.                 .execute();
  22.     }
  23. }
复制代码
执行,检察生成结果
3. 执行SQL分析打印

在我们日常开发工作当中,制止不了检察当前步伐所执行的SQL语句,以及相识它的执行时间,方便分析是否出现了慢SQL题目。我们可以利用MybatisPlus提供的SQL分析打印的功能,来获取SQL语句执行的时间。
由于该功能依赖于 p6spy 组件,所以需要在 pom.xml 中先引入该组件。
  1. <dependency>
  2.     <groupId>p6spy</groupId>
  3.     <artifactId>p6spy</artifactId>
  4.     <version>3.9.1</version>
  5. </dependency>
复制代码
在 application.yml中举行设置
将驱动和 url 修改
  1. spring:
  2.   datasource:
  3.     driver-class-name: com.p6spy.engine.spy.P6SpyDriver
  4.     url: jdbc:p6spy:mysql
复制代码

在 resources下,创建 spy.properties 设置文件。
  1. #3.2.1以上使用modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
  2. # 自定义日志打印
  3. logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
  4. #日志输出到控制台
  5. appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
  6. # 使用日志系统记录 sql
  7. #appender=com.p6spy.engine.spy.appender.Slf4JLogger
  8. # 设置 p6spy driver 代理
  9. deregisterdrivers=true
  10. # 取消JDBC URL前缀
  11. useprefix=true
  12. # 配置记录 Log 例外,可去掉的结果集error,info,batch,debug,statement,commit,rollback,result,resultset.
  13. excludecategories=info,debug,result,commit,resultset
  14. # 日期格式
  15. dateformat=yyyy-MM-dd HH:mm:ss
  16. # 实际驱动可多个
  17. #driverlist=org.h2.Driver
  18. # 是否开启慢SQL记录
  19. outagedetection=true
  20. # 慢SQL记录标准 2 秒
  21. outagedetectioninterval=2
复制代码
测试
执行查询所有的操作,可以看到sql语句的执行时间

4. 总结:


  • 注意:理解灰心锁和乐观锁:

    • 灰心锁: 灰心锁是在查询的时候就锁定数据,在这次请求未完成之前,不会释放锁。必须等到这次请求执行完毕以后,再释放掉锁,释放了锁之后,其他请求才可以对于这条数据完成读写。
    • 乐观锁: 乐观锁是通过表字段完成设计的,他的核心头脑是,在读取的时候不加锁,其他请求依然可以读取到这个数据,在修改的时候判断一个数据是否有被修改过,如果有被修改过,那本次请求的修改操作失败。

5. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表