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

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

@

目录
  • 七,MyBatis-Plus 扩展功能:乐观锁,代码生成器,执行SQL分析打印(实操详细使用)
  • 1. 乐观锁
  • 2. 代码生成器
  • 3. 执行SQL分析打印
  • 4. 总结:
  • 5. 最后:

1. 乐观锁

首先我们需要先了解开发中的一个常见场景,叫做并发请求。

并发请求就是在同一时刻有多个请求,同时请求服务器资源,如果是获取信息,没什么问题,但是如果是对于信息做修改操作,那就会出现问题。

这里我们举一个例子。比如:目前商品的库存只剩余 1件了,这个时候有多个用户都想要购买这件商品,都发起了购买商品的请求,那么能让这多个用户都购买到么,肯定是不行的,因为多个用户都买到了这件商品,那么就会出现超卖问题,库存不够时没法发货的。所以在开发中就要解决这种超卖的问题。

在这里插入图片描述

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

在这里插入图片描述

想要解决这类问题,最常见的就是加锁的思想,锁可以用验证在请求的执行过程中,是否有数据发生改变。

常见的数据库锁类型有两种,悲观锁和乐观锁。

一次完成的修改操作是:先查询数据,然后修改数据。

这样做的操作能够保证读取到的信息就是当前的信息,保证了信息的正确性,但是并发效率很低,在实际开发中使用悲观锁的场景很少,因为在并发时,我们是要保证效率的。

乐观锁: 乐观锁是通过表字段完成设计的,他的核心思想是,在读取的时候不加锁,其他请求依然可以读取到这个数据,在修改的时候判断一个数据是否有被修改过,如果有被修改过,那本次请求的修改操作失败。

具体的通过 SQL 是这样实现的,添加了一个 where version = 1

这样做的操作是不会对于数据读取产生影响,并发的效率较高,但是可能目前看到的数据并不是真实信息数据,是被修改之前的,但是在很多场景下是可以容忍的,并不是产生很大影响。例如:很多时候我们看到的是有库存,或者都加入都购物车,但是点进去以后库存没有了。

在数据库表中添加一个字段 version,表示版本,默认值是1

在这里插入图片描述

生成后的效果

在这里插入图片描述

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

在这里插入图片描述

因为要对每条修改语句完成语句的增强,这里我们通过拦截器的配置,让每条修改的 sql 语句在执行的时候,都加上版本控制的功能。

在这里插入图片描述

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();/*通过配置类来指定一个具体数据库的分页插件,因为不同的数据库的方言不同,具体涩会给你从的分页语句也会不同,这里我们指定数据库为 MySQL数据库*/mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁return mybatisPlusInterceptor;}}

测试效果,这里我们模拟先查询,再修改

@Test
void updateTest(){User user = userMapper.selectById(6L);user.setName("li");userMapper.updateById(user);
}

在这里插入图片描述

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

在这里插入图片描述

当我们完成修改时,他会将版本号 + 1

此时查看数据发现,更改姓名后,version已经为2了

在这里插入图片描述

接下来我们模拟一下,当出现多个修改请求的时候,是否能够做到乐观锁的效果。

乐观锁的效果是,一个请求在修改的过程中,是允许另一个请求查询的,但是修改时会通过版本号是否改变来决定是否修改,如果版本号变了,证明已经有请求修改过数据了,那这次修改不生效,如果版本号没有发生变化,那就完成修改。

在这里插入图片描述

package com.rainbowsea;import com.rainbowsea.bean.User;
import com.rainbowsea.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class LockTest {@Autowiredprivate UserMapper userMapper;@Testvoid updateTest2() {// 模拟操作1的查询操作User user1 = userMapper.selectById("5");System.out.println("查询结果:" + user1);// 模拟操作2的查询操作User user2 = userMapper.selectById("5");System.out.println("查询结果:" + user2);// 模拟操作2的修改操作user2.setName("liHua");userMapper.updateById(user2);// 模拟操作1的修改操作user1.setName("zhangsan");userMapper.updateById(user1);}}

我们来看下这段代码的执行过程,这段代码其实是两次操作,只不过操作1在执行的过程中,有操作2完成了对于数据的修改,这时操作1就无法再次进行修改了

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

2. 代码生成器

代码生成器和逆向工程的区别在于,代码生成器可以生成更多的结构,更多的内容,允许我们能够配置生成的选项更多。在这里我们演示一下代码生成器的用法。

参考官网,使用代码生成器需要引入两个依赖;

在这里插入图片描述

  <!--        mybatis-plus 的依赖--><!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3</version></dependency><!--freemarker模板依赖--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>

编写代码生成器代码

@SpringBootTest
class GeneratorApplicationTests {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false", "root", "root").globalConfig(builder -> {builder.author("powernode") // 设置作者//.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件.outputDir("D://"); // 指定输出目录}).packageConfig(builder -> {builder.parent("com.powernode") // 设置父包名.moduleName("mybatisplus") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径}).strategyConfig(builder -> {builder.addInclude("powershop_user") // 设置需要生成的表名.addTablePrefix("powershop"); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
}

执行,查看生成效果

3. 执行SQL分析打印

在我们日常开发工作当中,避免不了查看当前程序所执行的SQL语句,以及了解它的执行时间,方便分析是否出现了慢SQL问题。我们可以使用MybatisPlus提供的SQL分析打印的功能,来获取SQL语句执行的时间。

由于该功能依赖于 p6spy 组件,所以需要在 pom.xml 中先引入该组件。

在这里插入图片描述

<dependency><groupId>p6spy</groupId><artifactId>p6spy</artifactId><version>3.9.1</version>
</dependency>

application.yml中进行配置

将驱动和 url 修改

spring:datasource:driver-class-name: com.p6spy.engine.spy.P6SpyDriverurl: jdbc:p6spy:mysql

在这里插入图片描述

resources下,创建 spy.properties 配置文件。

在这里插入图片描述

#3.2.1以上使用modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger# 设置 p6spy driver 代理
deregisterdrivers=true# 取消JDBC URL前缀
useprefix=true# 配置记录 Log 例外,可去掉的结果集error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss# 实际驱动可多个
#driverlist=org.h2.Driver# 是否开启慢SQL记录
outagedetection=true# 慢SQL记录标准 2 秒
outagedetectioninterval=2

测试

执行查询所有的操作,可以看到sql语句的执行时间

在这里插入图片描述

4. 总结:

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

5. 最后:

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/806543.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加解密demo(java、php)

数据格式* @param args* 撞库---入参加密字段signs加密前格式** {* "mobileMask": "134123412**",* "city": "武汉",* "system": "qxh"* }** 撞库---返回加密字段signs加密前格式* {* "md5L…

Newstar Re wk1 wp

Newstar Re wk1 wpNewstar Re wk1 wp练一下markdown语法(有些地方明显是为了使用markdown语法而硬造的)begin 引导新手使用IDA Pro。用IDA Pro打开,根据英语引导可知flag分为三部分,依次寻找: 第一部分:点进&flag_part1,可找到第一部分。使用小端序存储所以要倒着…

《Java 基础篇》一:入门

Java 基础概念、运算符以及程序流程控制语句。Author: ACatSmiling Since: 2024-09-30bit 和 byte 计算机本质是一系列的电路开关。每个开关存在两种状态:开(on)和关(off)。如果电路是开的,它的值是 1,如果电路是关的,它的值是 0。一个 0 或者一个 1 存储为一个比特(b…

《Java 基础篇》二:面向对象

Java 面向对象的三条主线:类及类的成员、关键字和三大特征。Author: ACatSmiling Since: 2024-09-30概述 面向过程(POP)与面向对象(OOP):二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能…

[python] 基于PyOD库实现数据异常检测

PyOD是一个全面且易于使用的Python库,专门用于检测多变量数据中的异常点或离群点。异常点是指那些与大多数数据点显著不同的数据,它们可能表示错误、噪声或潜在的有趣现象。无论是处理小规模项目还是大型数据集,PyOD提供了50多种算法以满足用户的需求。PyOD的特点包括:统一…

Linux 万字入门教程

Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。0. 前言文章已经收录到 GitHub 个人博客项目,欢迎 Star: https://github.com/chenyl8848/chenyl8848.github.io或者访问网站,进行在线浏览:…

阿里面试:说说 jvm 锁的膨胀过程?锁内存怎么变化的?

文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,…

闭源与开源嵌入模型比较以及提升语义搜索效果的技术探讨

闭源与开源嵌入模型比较以及提升语义搜索效果的技术探讨上图为执行语义搜索前的聚类演示 ,嵌入技术是自然语言处理的核心组成部分。虽然嵌入技术的应用范围广泛,但在检索应用中的语义搜索仍是其最常见的用途之一。https://avoid.overfit.cn/post/38350e175fa0424b8c988ad9893…

20240903

mount 我们会惊奇的发现,无论网格在哪里,只要有山覆盖了,那么这里的贡献一定是 \(\sqrt{2}\),如下的图可以证明:那么我们就只用开一个线段树,维护的是最小值和最小值的出现次数,如果最小值不为 \(0\),那么这部风就没有贡献,反之贡献就要加上最小值的出现次数 细节 由于我们可以…

南沙C++信奥赛陈老师解一本通题: 1963:【13NOIP普及组】小朋友的数字

​【题目描述】有 nn 个小朋友排成一列。每个小朋友手上都有一个数字,这个数字可正可负。规定每个小朋友的特征值等于排在他前面(包括他本人)的小朋友中连续若干个(最少有一个)小朋友手上的数字之和的最大值。 作为这些小朋友的老师,你需要给每个小朋友一个分数,分数是这…

Python工程数学2程序开胃菜(上)

2 数学程序开胃菜 在上一章中( https://mp.weixin.qq.com/s/kKenXcEXIeLd_u_2kymF8A ),我们介绍了python的IDE;用numpy实现向量计算;用Matplotlib绘图;用sympy实现微积分和求导;用SciPy实现积分;用VPython实现弹跳球动画。在本章中,您将了解 Python 命令式编程风格的线…

河道水位识别系统

河道水位识别系统采用视频智能分析功能,河道水位识别系统利用前端摄像头实时获取前端视频视频后,自动识别水尺位置,并在水尺区域将水尺进行数字分割,河道水位识别系统然后再通过水位线的位置,通过AI图像识别技术将数字与水位线位置结合对别,即可识别出水尺读数。河道水位…