MybatisPlus(5)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MybatisPlus(5)

一、乐观锁(update)🍭

业务并发现象带来的问题: 秒杀。

我们应该都遇过买东西限量秒杀吧,这个时候这么多人一起抢,我们应该怎么去实现秒杀程序呢?

下面我们会讲解2000访问量的秒杀实现,如果是更多人的话就应该使用其他更好的方法了。

1、添加字段和实体类属性🍉

添加version字段,默认值为1

image.png

实体类属性也添加应该version属性:


package com.example.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
@Data
/*@TableName("tbl_user")*/
public class User {
    @TableId(type= IdType.ASSIGN_ID)
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false)
    private String password;
    private Integer age;
    private String tel;
    /*@TableLogic(value = "0",delval = "1")*/
    private Integer deleted;
    @Version
    private Integer version;
    @TableField(exist = false)
    private Integer online;
}

2、@Version原理🍉

当人人去进行秒杀时,成功抢到商品的用户,会更新用户的version值


update set_abc=1,version = version + 1 where version=1

如上面这个SQL一样。当一个仅剩的一个商品被抢走,这个version值就会变化,其他人就会显示抢不到商品。

添加乐观锁拦截器(和分页功能一样)🍓

使用这个和分页功能一样,需要添加拦截器:


package com.example.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor(){
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //2.添加具体的拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        //3、添加乐观锁拦截器
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mpInterceptor;
    }
}

3、测试代码🍓

我们去修改用户id=2的用户名:


@Test
    void testUpdate(){
        User user=new User();
        user.setId(2L);
        user.setName("编程");
        userDao.updateById(user);
    }

运行发现,version值并没有发生改变:

image.png

这是因为我们没有去添加version值,便无法改变version值。


@Test
    void testUpdate(){
        User user=new User();
        user.setId(2L);
        user.setVersion(1);
        user.setName("编程");
        userDao.updateById(user);
    }

添加用户的version发现,进行修改操作之后version值+1了:

image.png

但是这样手动添加version值很麻烦,我们可以先查询用户信息,然后去进行修改,也是可以的:


@Test
    void testUpdate(){
        //1.先通过要修改的数据id将当前数据查询出来
        User user = userDao.selectById(2L);
        //2.将要修改的属性逐一设置进去
        user.setName("编程1号");
        userDao.updateById(user);
    }

可以看到version经过用户修改又加了1。

image.png

4、秒杀测试🍓

我们前后修改两次用户名,看最终结果如何:


@Test
    void testUpdate(){
        //1.先通过要修改的数据id将当前数据查询出来
        User user = userDao.selectById(2L);     //version=3
        User user2 = userDao.selectById(2L);    //version=3
        user2.setName("编程 aaa");
        userDao.updateById(user2);              //version=>4
        user.setName("编程 bbb");
        userDao.updateById(user);               //verion=3?条件还成立吗?
    }

可以看到只修改了一次,用户名修改为了 编程 aaa ,而后面的修改操作未进行:

image.png

image.png

这和我们上面说的情况是一样的,用户信息进行了修改,version值也会加一,因为你一开始查询到的version值为3,这个时候version已经变成了4,就无法进行修改成为 编程 bbb 了。

二、代码生成器🍭

1、模板🍉

既然是代码生成器,那肯定是有模板的,那我们来看看UserDao,观察看看,哪些是模板里的,哪些是需要更改的。


package com.example.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.domain.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao extends BaseMapper {
}

看下面,对于不同的Dao类只需要将下面红框框里的东西替换就行,其他的就是模板。换句话说我们只要将下面红框框里面的东西替换,又是一个新的Dao类。

image.png

不仅仅是Dao类实体类也可以提取出模板。

2、代码生成器🍉

模板:MyBatisPlus提供

数据库相关配置:读取数据库获取信息

开发者自定义配置:手工配置

Ⅰ、配置🍓

我们新建一个SpringBoot项目:

image.png

pom.xml:其中有所需要的代码生成器和velocity模板引擎以及其他需要的配置文件


"1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.7.14version>
        <relativePath/> 
    parent>
    <groupId>com.examplegroupId>
    <artifactId>mybatis-plusartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>mybatis-plusname>
    <description>mybatis-plusdescription>
    <properties>
        <java.version>1.8java.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.4.1version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.16version>
        dependency>
        <dependency>
            <groupId>com.mysqlgroupId>
            <artifactId>mysql-connector-jartifactId>
            <scope>runtimescope>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-generatorartifactId>
            <version>3.4.1version>
        dependency>
        <dependency>
            <groupId>org.apache.velocitygroupId>
            <artifactId>velocity-engine-coreartifactId>
            <version>2.3version>
        dependency>
    dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

Generator类:添加数据库配置


package com.example;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
public class Generator {
    public static void main(String[] args) {
        AutoGenerator autoGenerator=new AutoGenerator();
        DataSourceConfig dataSource=new DataSourceConfig();
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/ku2022?characterEncoding=utf8");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        autoGenerator.setDataSource(dataSource);
        autoGenerator.execute();
    }
}

运行之后会给我打开一个文件夹:

image.png

可以发现多了一个com文件夹,我们打开里面的controller文件夹,可以发现它给这个库里面每一个表都生成了一个.java文件,这个就是给我们生成的代码:

image.png

但是这个东西生成的是不正确的,所以我们将这个文件夹删除掉。

Ⅱ、正确生成代码 🍓

我们应该添加其他配置,让他生成在正确的位置:


package com.example;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
public class CodeGenerator {
    public static void main(String[] args) {
        //1.获取代码生成器的对象
        AutoGenerator autoGenerator = new AutoGenerator();
        //设置数据库相关配置
        DataSourceConfig dataSource = new DataSourceConfig();
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/ku2022?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        autoGenerator.setDataSource(dataSource);
        //设置全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        //输出的位置
        globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");    //设置代码生成位置
        globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setAuthor("热爱编程的林兮");    //设置作者
        globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件
        globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
        globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
        autoGenerator.setGlobalConfig(globalConfig);
        //2.执行生成操作
        autoGenerator.execute();
    }
}

我们看到上面,点开GlobalConfig源码:

image.png

默认生成代码在D盘。

Ⅲ、生成的代码1🍓

我们运行代码:

image.png

可以看到在Java目录下的con文件夹生成了一个baomidou文件夹。

Ⅳ、生成的代码2🍓

我们继续在CodeGenerator添加新配置:


//设置包名相关配置
        PackageConfig packageInfo = new PackageConfig();
        packageInfo.setParent("com.aaa");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        packageInfo.setEntity("domain");    //设置实体类包名
        packageInfo.setMapper("dao");   //设置数据层包名
        autoGenerator.setPackageInfo(packageInfo);

我们把之前的代码(baomidou)删除掉,重新运行代码。

image.png

可以发现重新生成了一个名字为aaa文件夹,不再是原来的名字了。还有实体类的包名也修改了,变成了domin,数据层包名也变成了dao。

Ⅴ、生成的代码3 🍓


//策略设置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("tbl_user");  //设置当前参与生成的表名,参数为可变参数
        strategyConfig.setTablePrefix("tbl_");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
        strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格
        strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
        strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
        strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
        autoGenerator.setStrategy(strategyConfig);

之前库里面有五个表,这次通过上面代码我只生成了tbl_user表的代码(只想生成我指定表的代码),而且表的实体类加了@Data注解(启用了lombok),设置了乐观锁字段名还有逻辑删除字段名,以及删除了数据表的tbl_前缀。

image.png



相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
SQL 测试技术 数据库
一篇文章带你学会MybatisPlus~(三)
一篇文章带你学会MybatisPlus~
|
7月前
|
Java 数据库连接 mybatis
MybatisPlus(1)
MybatisPlus(1)
93 0
MybatisPlus(1)
|
7月前
|
Java 测试技术 数据库连接
【MyBatisPlus】MyBatisPlus 整合开发
【1月更文挑战第19天】【MyBatisPlus】MyBatisPlus 整合开发
|
SQL Java 数据库连接
Springoot 整合 MyBatisPlus
SpringBoot 整合 MyBatisPlus 的基本步骤,以及MyBatisPlus的基本使用步骤
115 0
|
7月前
|
SQL 监控 数据库
MybatisPlus入门(下)
MybatisPlus入门教程中介绍了如何使用拦截器和性能分析插件。配置拦截器只需添加`PaginationInterceptor`,测试分页查询显示底层使用了`limit`。逻辑删除功能通过`TableLogic`注解和`LogicSqlInjector`实现,性能分析插件`PerformanceInterceptor`用于监控SQL执行时间,超过设定值会抛出异常。条件构造器如`QueryWrapper`提供便捷的查询条件设置,支持多种比较操作。
|
7月前
|
数据库
|
7月前
|
存储 算法 Java
一篇文章带你学会MybatisPlus~(二)
一篇文章带你学会MybatisPlus~
435 0
|
7月前
|
SQL Java 数据库连接
一篇文章带你学会MybatisPlus~(一)
一篇文章带你学会MybatisPlus~
|
7月前
|
XML SQL Java
MybatisPlus(2)
MybatisPlus(2)
88 0
MybatisPlus(2)
|
7月前
|
算法 数据库 SQL
MybatisPlus(4)
MybatisPlus(4)
77 0
MybatisPlus(4)