MySQL功能测试-之应用工程

MySQL功能测试-之应用工程

  • 前言
  • pom.xml
  • application.yml 文件
  • common.vo 包
    • ResultVO
  • config 包
    • properties 包
      • DruidConfigProperty
      • DruidMonitorProperty
    • AutoFillMetaObjectHandler
    • DruidConfig
    • FluxConfiguration
    • MyBatisPlusConfig
  • controller 包
    • ClientController
    • DruidController
    • WebFluxController
  • entity 包
    • ClientEntity
  • exception 包
    • code 包
      • CRUDStatus
    • BizException
    • GlobalException
  • mapper 包
    • ClientMapper
  • service 包
    • impl 包
    • ClientService
  • DruidApplication
  • resource/mapper 包
    • ClientMapper.xml

前言

应用工程的建设,主要是为了支撑 MySQL 数据库的一些测试场景,例如:

  1. 应用实时写入数据库时,进行修改表结构,查看锁的情况。
  2. 应用实时写入数据库时,数据库增量备份/恢复测试。
  3. 应用实时写入数据库时,数据库主从切换脚本测试。等等…各种场景。

当前工程是在《SpringBoot【2】集成 MyBatis Plus》基础上,进行代码迭代开发的,MySQL 数据库相关测试功能所涉及应用仅此一个,故此应用后续会不断完善,也会同步更新此文档。

目前完成后的项目截图如下:
在这里插入图片描述

pom.xml

<?xml version="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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.12.RELEASE</version>
        <relativePath />
    </parent>


    <groupId>com.junjiu.springboot.druid</groupId>
    <artifactId>junjiu-springboot-druid</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <mysql.connector.java.version>8.0.28</mysql.connector.java.version>
        <mybatis.plus.boot.starter.version>3.3.1</mybatis.plus.boot.starter.version>
        <druid.version>1.2.13</druid.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>


        <!-- MySQL驱动依赖. -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.connector.java.version}</version>
        </dependency>
        <!-- mybatis-plus 依赖
            https://baomidou.com/getting-started/
        -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version> ${mybatis.plus.boot.starter.version} </version>
        </dependency>

        <!-- Druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- lombok 依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- 阿里巴巴 fastjson -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.25</version>
        </dependency>
    </dependencies>

</project>

application.yml 文件

# 端口
server:
  port: 5826

spring:
  application:
    # 应用名称
    name: junjiu-springboot-druid
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.88.54:3306/ideadb?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false
      username: fid_idea
      password: 123456
      initial-size: 10
      max-active: 100
      min-idle: 10
      max-wait: 60000
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      max-evictable-idle-time-millis: 600000
      validation-query: SELECT 1 FROM DUAL
      # validation-query-timeout: 5000
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      #filters: #配置多个英文逗号分隔(统计,sql注入,log4j过滤)
      filters: stat,wall
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*

# 监控页面配置.
jj:
  druid:
    monitor:
      login-username: root
      login-password: 123456
      reset-enable: false

# mybatis plus 配置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0
  mapper-locations: classpath*:/mapper/*Mapper.xml
  type-aliases-package: com.junjiu.springboot.druid.entity

common.vo 包

ResultVO

package com.junjiu.springboot.druid.common.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * program: junjiu-springboot-druid
 * ClassName: ResultVO
 * description: 定义统一响应 Vo
 *
 * @author: 君九
 * @create: 2024-06-15 10:11
 * @version: 1.0
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultVO implements Serializable {


    private Integer code;

    private String message;

    private Object data;

    /**
     * 状态码
     */
    enum Status {

        SUCCESS(200, "成功"),
        SERVER_ERROR(500, "服务器内部错误");

        private Integer code;
        private String message;

        Status(Integer code, String message) {
            this.code = code;
            this.message = message;
        }

        public Integer getCode() {
            return this.code;
        }

        public String getMessage() {
            return this.message;
        }

    }

    public static ResultVO success(String message) {
        return new ResultVO(Status.SUCCESS.code, message, null);

    }
    public static ResultVO success(String message, Object data) {
        return new ResultVO(Status.SUCCESS.code, message, data);
    }

    public static ResultVO error(String message) {
        return new ResultVO(Status.SERVER_ERROR.code, message, null);
    }

    public static ResultVO error(String message, Object data) {
        return new ResultVO(Status.SERVER_ERROR.code, message, data);
    }

    public static ResultVO error(Integer code, String message, Object data) {
        return new ResultVO(code, message, data);
    }

    public static ResultVO error(Integer code, String message) {
        return new ResultVO(code, message, null);
    }


}

config 包

properties 包

DruidConfigProperty

package com.junjiu.springboot.druid.config.properties;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * program: junjiu-springboot-druid
 * ClassName: DruidConfigProperty
 * description:
 *
 * @author: 君九
 * @create: 2024-05-26 13:19
 * @version: 1.0
 **/
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "spring.datasource.druid")
public class DruidConfigProperty {

    private String url;
    private String username;
    private String password;
    private String driverClassName;
    private int initialSize;
    private int maxActive;
    private int minIdle;
    private int maxWait;
    private boolean poolPreparedStatements;
    private int maxPoolPreparedStatementPerConnectionSize;
    private int timeBetweenEvictionRunsMillis;
    private int minEvictableIdleTimeMillis;
    private int maxEvictableIdleTimeMillis;
    private String validationQuery;
    private boolean testWhileIdle;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private String filters;
    private String connectionProperties;

}

DruidMonitorProperty

package com.junjiu.springboot.druid.config.properties;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * program: junjiu-springboot-druid
 * ClassName: DruidMonitorProperty
 * description:
 *
 * @author: 君九
 * @create: 2024-05-26 13:27
 * @version: 1.0
 **/
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "jj.druid.monitor")
public class DruidMonitorProperty {

    private String loginUsername;
    private String loginPassword;
    private String resetEnable;

}

AutoFillMetaObjectHandler

package com.junjiu.springboot.druid.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * program: junjiu-springboot-druid
 * ClassName: AutoFillMetaObjectHandler
 * description:
 *
 * @author: 君九
 * @create: 2024-06-12 22:52
 * @version: 1.0
 **/
@Component
public class AutoFillMetaObjectHandler  implements MetaObjectHandler {

    /**
     * 新增数据时,自动填充创建时间+修改时间 为当前时间。
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createdTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updatedTime", LocalDateTime.class, LocalDateTime.now());
    }

    /**
     * 更新数据时,自动填充创建时间+修改时间 为当前时间。
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "updatedTime", LocalDateTime.class, LocalDateTime.now());
    }
}

DruidConfig

package com.junjiu.springboot.druid.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.junjiu.springboot.druid.config.properties.DruidConfigProperty;
import com.junjiu.springboot.druid.config.properties.DruidMonitorProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * program: junjiu-springboot-druid
 * ClassName: DruidConfig
 * description: Druid 配置文件
 *
 * @author: 君九
 * @create: 2024-05-26 13:16
 * @version: 1.0
 **/
@Configuration
public class DruidConfig {

    @Autowired
    DruidConfigProperty druidConfigProperty;

    @Autowired
    DruidMonitorProperty druidMonitorProperty;

    /**
     * Druid 连接池配置
     */
    @Bean
    public DruidDataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(druidConfigProperty.getUrl());
        datasource.setUsername(druidConfigProperty.getUsername());
        datasource.setPassword(druidConfigProperty.getPassword());
        datasource.setDriverClassName(druidConfigProperty.getDriverClassName());
        datasource.setInitialSize(druidConfigProperty.getInitialSize());
        datasource.setMinIdle(druidConfigProperty.getMinIdle());
        datasource.setMaxActive(druidConfigProperty.getMaxActive());
        datasource.setMaxWait(druidConfigProperty.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(druidConfigProperty.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(druidConfigProperty.getMinEvictableIdleTimeMillis());
        datasource.setMaxEvictableIdleTimeMillis(druidConfigProperty.getMaxEvictableIdleTimeMillis());
        datasource.setValidationQuery(druidConfigProperty.getValidationQuery());
        datasource.setTestWhileIdle(druidConfigProperty.isTestWhileIdle());
        datasource.setTestOnBorrow(druidConfigProperty.isTestOnBorrow());
        datasource.setTestOnReturn(druidConfigProperty.isTestOnReturn());
        datasource.setPoolPreparedStatements(druidConfigProperty.isPoolPreparedStatements());
        datasource.setMaxPoolPreparedStatementPerConnectionSize(druidConfigProperty.getMaxPoolPreparedStatementPerConnectionSize());
        try {
            datasource.setFilters(druidConfigProperty.getFilters());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        datasource.setConnectionProperties(druidConfigProperty.getConnectionProperties());
        return datasource;
    }

    /**
     * JDBC操作配置
     */
    @Bean
    public JdbcTemplate jdbcTemplate (@Autowired DruidDataSource dataSource){
        return new JdbcTemplate(dataSource) ;
    }

    /**
     * 配置 Druid 监控界面
     */
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
        //设置控制台管理用户
        servletRegistrationBean.addInitParameter("loginUsername",druidMonitorProperty.getLoginUsername());
        servletRegistrationBean.addInitParameter("loginPassword",druidMonitorProperty.getLoginPassword());
        // 是否可以重置数据
        servletRegistrationBean.addInitParameter("resetEnable",druidMonitorProperty.getResetEnable());
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean statFilter(){
        //创建过滤器
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        //设置过滤器过滤路径
        filterRegistrationBean.addUrlPatterns("/*");
        //忽略过滤的形式
        filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }

}

FluxConfiguration

package com.junjiu.springboot.druid.config;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Bean;
import reactor.core.publisher.DirectProcessor;
import reactor.core.publisher.FluxSink;


/**
 * program: junjiu-springboot-druid
 * ClassName: FluxConfiguration
 * description:
 *
 * @author: 君九
 * @create: 2024-06-15 12:16
 * @version: 1.0
 **/
@Configuration
public class FluxConfiguration {

    @Bean
    public DirectProcessor<String> directProcessor() {
        return DirectProcessor.create();
    }

    @Bean
    public FluxSink<String> fluxSink(DirectProcessor<String> directProcessor) {
        return directProcessor.sink();
    }
}

MyBatisPlusConfig

package com.junjiu.springboot.druid.config;

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * program: junjiu-springboot-druid
 * ClassName: MyBatisPlusConfig
 * description:
 *
 * @author: 君九
 * @create: 2024-06-12 22:49
 * @version: 1.0
 **/
@Configuration
public class MyBatisPlusConfig {


    @Bean
    public PaginationInterceptor paginationInterceptor() {

        return new PaginationInterceptor();
    }

    /**
     *  自动填充功能
     * @return
     */
    @Bean
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new AutoFillMetaObjectHandler());
        return globalConfig;
    }

}

controller 包

ClientController

package com.junjiu.springboot.druid.controller;

import com.junjiu.springboot.druid.common.vo.ResultVO;
import com.junjiu.springboot.druid.entity.ClientEntity;
import com.junjiu.springboot.druid.service.ClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.time.Duration;

/**
 * program: junjiu-springboot-druid
 * ClassName: ClientController
 * description:
 *
 * @author: 君九
 * @create: 2024-06-12 22:59
 * @version: 1.0
 **/
@RestController
@RequestMapping("/client")
public class ClientController {

    @Autowired
    private ClientService clientService;

    /**
     * 测试添加数据.
     * @return
     */
    @RequestMapping("/testAdd")
    public String testAdd() {

        ClientEntity clientEntity = new ClientEntity();
        clientEntity.setClientId(1001L);
        clientEntity.setNickName("九皇叔叔");
        clientEntity.setRealName("君九");
        clientEntity.setUserNo("JunJiu");
        clientEntity.setUserPassword("123456");

        clientService.save(clientEntity);

        return "Success.";
    }


    /**
     * 我当前做测试,传入 loop、threadSize 一定有值,不在校验了
     *
     * @param loop 是否循环
     * @param threadSize 线程个数.
     * @return
     */
    @GetMapping("/setAddRandomData/{loop}/{threadSize}")
    public ResultVO setAddRandomData(
            @PathVariable("loop") Boolean loop,
            @PathVariable("threadSize") Integer threadSize
    ) {


        clientService.setAddRandomData(loop, threadSize);

        return ResultVO.success("操作成功.loop=" + loop);
    }

}

DruidController

package com.junjiu.springboot.druid.controller;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * program: junjiu-springboot-druid
 * ClassName: DruidController
 * description:
 *
 * @author: 君九
 * @create: 2024-05-26 13:32
 * @version: 1.0
 **/
@RestController
public class DruidController {

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private DruidDataSource druidDataSource;

    /**
     * 测试 Druid
     * @return
     */
    @GetMapping("/test")
    public String testDruid() {

        String sql = "select version()";
        String result = jdbcTemplate.queryForObject(sql, String.class);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return "Success.".concat(simpleDateFormat.format(new Date())).concat(":").concat(result);
    }

    /**
     * 测试连接池.
     *  查看 performance_schema.threads 情况.
     * @param size
     * @return
     */
    @GetMapping("/mutix/{size}")
    public String testDruidMutix(@PathVariable("size") Integer size) {
        for(int k = 0; k < size; k++) {
            new Thread(() -> {
                String sql = "select '你也可以通过操作系统级别的资源限制来控制 MySQL 进程的内存使用情况。具体的操作方式会根据操作系统的不同而有所不同,比如在 Linux 中可以使用 ulimit 命令来设置进程的资源限制。'";
                String result = jdbcTemplate.queryForObject(sql, String.class);
                System.out.println(Thread.currentThread().getName() + ":" + result);
            }).start();
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return "Success.".concat(simpleDateFormat.format(new Date()));
    }
}

WebFluxController

package com.junjiu.springboot.druid.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.time.Duration;

/**
 * program: junjiu-springboot-druid
 * ClassName: WebFluxController
 * description:
 *
 * @author: 君九
 * @create: 2024-06-15 11:26
 * @version: 1.0
 **/
@RestController
public class WebFluxController {

    @GetMapping("/data")
    public Flux<String> streamData() {
        // 模拟生成实时数据流
        return Flux.just("Data 1", "Data 2", "Data 3", "Data 4").delayElements(Duration.ofSeconds(1));
    }
}

entity 包

ClientEntity

package com.junjiu.springboot.druid.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * program: junjiu-springboot-druid
 * ClassName: ClientEntity
 * description:
 *
 * @author: 君九
 * @create: 2024-06-12 22:55
 * @version: 1.0
 **/
@Data
@TableName("client")
public class ClientEntity implements Serializable {

    /**
     * -- 1 -* 客户表
     * create table client(
     *    id bigint not null primary key auto_increment comment '自增ID',
     *    client_id bigint not null comment 'ID编号',
     *    user_no varchar(30) comment '账号',
     *    user_password varchar(60) comment '密码',
     *    nick_name varchar(30) comment '昵称',
     *    real_name varchar(30) comment '真实姓名',
     *    created_time datetime default now() comment '创建时间',
     *    upated_time datetime default now() comment '更新时间'
     * );
     */

    private Long id;
    private Long clientId;
    private String userNo;
    private String userPassword;
    private String nickName;
    private String realName;
    private Date createdTime;
    private Date updatedTime;

}

exception 包

code 包

CRUDStatus

package com.junjiu.springboot.druid.exception.code;

/**
 * program: junjiu-springboot-druid
 * ClassName: CRUDStatus
 * description: CRUD操作通用状态码.
 *
 * @author: 君九
 * @create: 2024-06-15 10:09
 * @version: 1.0
 **/
public enum CRUDStatus {

    // 添加成功
    SUCCESS_INSERT(100001, "添加成功"),
    // 添加失败
    FAIL_INSERT(100002, "添加失败"),
    // 修改成功
    SUCCESS_UPDATE(100003, "修改成功"),
    // 修改失败
    FAIL_UPDATE(100004, "修改失败"),
    // 删除成功
    SUCCESS_DELETE(100005, "删除成功"),
    // 删除失败
    FAIL_DELETE(100006, "删除失败"),
    // 未查询到数据
    NOT_FOUND(100007, "未查询到数据"),
    // 非法数据信息
    ILLEGAL_ARGUMENT(100008, "非法数据信息");

    private Integer code;
    private String message;

    CRUDStatus(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

}

BizException

package com.junjiu.springboot.druid.exception;

import lombok.Data;

/**
 * program: junjiu-springboot-druid
 * ClassName: BizException
 * description: 定义业务类统一异常类
 *
 * @author: 君九
 * @create: 2024-06-15 10:08
 * @version: 1.0
 **/
@Data
public class BizException extends RuntimeException {

    private Integer code;
    private String message;

    public BizException(String message) {
        super(message);
        this.message = message;
    }

    public BizException(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public BizException(String message, Exception exception) {
        super(message, exception);
        this.message = message;
    }

    public BizException(Integer code, String message, Exception exception) {
        super(message, exception);
        this.code = code;
        this.message = message;
    }
}

GlobalException

package com.junjiu.springboot.druid.exception;

/**
 * program: junjiu-springboot-druid
 * ClassName: GlobalException
 * description:
 *
 * @author: 君九
 * @create: 2024-06-15 10:08
 * @version: 1.0
 **/
public class GlobalException {
}

mapper 包

ClientMapper

package com.junjiu.springboot.druid.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.junjiu.springboot.druid.entity.ClientEntity;
import org.apache.ibatis.annotations.Mapper;

/**
 * program: junjiu-springboot-druid
 * ClassName: ClientMapper.xml
 * description:
 *
 * @author: 君九
 * @create: 2024-06-12 22:57
 * @version: 1.0
 **/
@Mapper
public interface ClientMapper extends BaseMapper<ClientEntity> {
}

service 包

impl 包

package com.junjiu.springboot.druid.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.junjiu.springboot.druid.entity.ClientEntity;
import com.junjiu.springboot.druid.exception.BizException;
import com.junjiu.springboot.druid.exception.code.CRUDStatus;
import com.junjiu.springboot.druid.mapper.ClientMapper;
import com.junjiu.springboot.druid.service.ClientService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * program: junjiu-springboot-druid
 * ClassName: ClientServiceImpl
 * description:
 *  客户业务实现类.
 *
 * @author: 君九
 * @create: 2024-06-12 22:58
 * @version: 1.0
 **/
@Service
public class ClientServiceImpl extends ServiceImpl<ClientMapper, ClientEntity> implements ClientService {

    private ThreadLocal<Thread> threadLocal = new ThreadLocal<>(); // ThreadLocal 存储每个线程
    private volatile boolean loop = true; // 用于控制线程循环的共享变量




    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setAddRandomData(Boolean loop, Integer threadSize) {
        this.loop = loop; // 设置共享变量的初始值
        CompletableFuture<?>[] futures = new CompletableFuture[threadSize];

        if(loop) {
            for (int i = 0; i < threadSize; i++) {
                final int threadNumber = i + 1;
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    while (this.loop) {

                        // 创建随机的 ClientEntity 对象
                        ClientEntity client = new ClientEntity();
                        client.setClientId(Thread.currentThread().getId()); // 设置随机的 clientId
                        client.setUserNo(Thread.currentThread().getName()); // 将 userNo 设置为当前线程名称
                        client.setUserPassword(generateRandomString(16)); // 生成随机密码
                        client.setNickName("NickName_" + Thread.currentThread().getId()); // 设置昵称
                        client.setRealName("RealName_" + Thread.currentThread().getId()); // 设置真实姓名

                        try {
                            // 将生成的 ClientEntity 插入数据库
                            baseMapper.insert(client);
                        } catch (Exception exception) {
                            exception.printStackTrace();
                            throw new BizException(CRUDStatus.FAIL_DELETE.getCode(), CRUDStatus.FAIL_INSERT.getMessage(), exception);
                        }

                        Random random = new Random();
                        int randomData = random.nextInt(1000);
                        try {
                            Thread.sleep(randomData);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });

                futures[i] = future.exceptionally(ex -> {
                    // 异常处理
                    if (ex.getCause() instanceof BizException) {
                        throw (BizException) ex.getCause(); // 将 BizException 抛给父线程
                    } else {
                        // 其他异常,可以选择处理或包装成自定义异常
                        throw new RuntimeException("Unexpected error occurred in thread " + threadNumber, ex);
                    }
                });

                threadLocal.set(Thread.currentThread());
            }

            try {
                CompletableFuture.allOf(futures).get(); // 等待所有 CompletableFuture 完成
            } catch (InterruptedException | ExecutionException e) {
                // 处理异常
                // e.printStackTrace();
                System.out.println(e.getMessage());
            }

        } else {
            this.loop = false; // 设置 loop 为 false,停止所有线程的循环
        }
    }

    /**
     * 生成指定长度的随机字符串(仅用于示例,实际应用中需要更复杂的实现)
     * @param length 字符串长度
     * @return 随机字符串
     */
    private String generateRandomString(int length) {
        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(characters.length());
            sb.append(characters.charAt(index));
        }
        return sb.toString();
    }

}

ClientService

package com.junjiu.springboot.druid.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.junjiu.springboot.druid.entity.ClientEntity;

/**
 * program: junjiu-springboot-druid
 * ClassName: ClientService
 * description:
 *  客户端业务接口.
 *
 * @author: 君九
 * @create: 2024-06-12 22:57
 * @version: 1.0
 **/
public interface ClientService extends IService<ClientEntity> {

    /**
     * 随机添加数据,用于模拟:应用实时添加数据情况,对 MySQL 数据库进行备份恢复、调整字段长度等场景。
     *
     * --- 目标:
     * 1.根据传入的线程个数,开启多线程。
     * 2.产生随机等待时长,使线程等待后,在执行添加数据操作。
     * 3.可手动开启/暂停,数据入库。
     *
     * @param loop 循环.
     * @param threadSize 线程个数.
     *
     */
    void setAddRandomData(Boolean loop, Integer threadSize);


}

DruidApplication

package com.junjiu.springboot.druid;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * program: junjiu-springboot-druid
 * ClassName: DruidApplication
 * description:
 *
 * @author: 君九
 * @create: 2024-05-26 13:13
 * @version: 1.0
 **/
@SpringBootApplication
public class DruidApplication {
    public static void main(String[] args) {

        SpringApplication.run(DruidApplication.class);
    }
}

resource/mapper 包

ClientMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.junjiu.springboot.druid.mapper.ClientMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.junjiu.springboot.druid.entity.ClientEntity">
        <id column="id" property="id" />
        <result column="client_id" property="clientId" />
        <result column="user_no" property="userNo" />
        <result column="user_password" property="userPassword" />
        <result column="nick_name" property="nickName" />
        <result column="real_name" property="realName" />
        <result column="created_time" property="createdTime" />
        <result column="updated_time" property="updatedTime" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, client_id, user_no, user_password, nick_name, real_name, created_time, updated_time
    </sql>

</mapper>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能产品经理,行业巨头争夺的稀缺人才

前言 在当今这个由数据驱动的时代&#xff0c;人工智能&#xff08;AI&#xff09;正迅速成为推动各行各业创新的核心力量。随着行业巨头纷纷布局人工智能领域&#xff0c;对于专业人才的需求也日益增长。特别是人工智能产品经理这一岗位&#xff0c;缺口高达6.8万&#xff0c…

[机器学习算法] Q学习

Q学习&#xff08;Q-Learning&#xff09;是一种基于值的强化学习算法&#xff0c;用于在给定状态下选择动作&#xff0c;以最大化累积奖励。它通过不断更新一个称为Q表&#xff08;Q-table&#xff09;的表来学习动作的价值。 一、理解基本概念 状态 (State, S) 这是环境的…

戏剧之家杂志戏剧之家杂志社戏剧之家编辑部2024年第14期目录

文艺评论 南戏瓯剧跨文化传播研究 陈晓东;高阳;许赛梦; 3-7 论互联网时代的戏剧传播与批评——以西法大剧社和南山剧社为例 邬慧敏; 8-10 “左手荒诞&#xff0c;右手温情”——《西西弗神话》在戏剧《第七天》中的接受探究 赵稳稳; 11-13 戏剧研讨《戏剧之家》投稿…

计算机毕业设计师hadoop+spark+hive知识图谱医生推荐系统 医生数据分析可视化大屏 医生爬虫 医疗可视化 医生大数据 机器学习 大数据毕业设计

流程&#xff1a; 1.Python爬虫采集中华健康网约10万医生数据&#xff0c;最终存入mysql数据库&#xff1b; 2.使用pandasnumpy/hadoopmapreduce对mysql中的医生数据进行数据分析&#xff0c;使用高德地图解析地理位置&#xff0c;并将结果转入.csv文件同时上传到hdfs文件系统&…

Github生成Personal access tokens及在git中使用

目录 生成Token 使用Token-手工修改 使用Token-自动 生成Token 登录GitHub&#xff0c;在GitHub右上角点击个人资料头像&#xff0c;点击Settings → Developer Settings → Personal access tokens (classic)。 在界面上选择点击【Generate new token】&#xff0c;填写如…

西米支付:【风控升级】同一商户集中交易,将会限制正常用卡

支付公司风控策略再升级&#xff01;近日&#xff0c;有某支付公司代理透漏&#xff0c;客户反馈机器突然不能刷卡了&#xff0c;换卡也无法交易&#xff0c;交易均提示06-超出商户限额&#xff0c;然而该款机器刷卡限额为单日30万&#xff0c;单月300万&#xff0c;客户并未触…

ctr/cvr预估之FM模型

ctr/cvr预估之FM模型 在数字化时代&#xff0c;广告和推荐系统的质量直接影响着企业的营销成效和用户体验。点击率&#xff08;CTR&#xff09;和转化率&#xff08;CVR&#xff09;预估作为这些系统的核心组件&#xff0c;其准确性至关重要。传统的机器学习方法&#xff0c;如…

怎么把答案去掉打印?超详细步骤告诉你!

在数字化教育日益普及的今天&#xff0c;我们时常需要在电子试卷和纸质试卷之间进行转换。然而&#xff0c;许多时候我们并不需要答案部分&#xff0c;这就需要我们掌握一些工具来去除答案&#xff0c;以便打印出纯净的试卷。本文将为您详细介绍如何使用试卷星、拍试卷以及WPS …

如何避免群发引起反感?

微信群发信息引起反感主要是因为缺乏情感&#xff0c;尽管最初微信群发旨在传递有价值信息&#xff0c;但由于滥用&#xff0c;现在人们对其印象非常负面。但是&#xff0c;还是有办法挽救的&#xff01; 群发消息时按照这3个标准发&#xff0c;可以避免被反感。 1、短信群发目…

SDK编译IO Domain电压选择

开源鸿蒙硬件方案领跑者 触觉智能 本文适用于在Purple Pi OH开发板进行分区镜像烧录。触觉智能的Purple Pi OH鸿蒙开源主板&#xff0c;是华为Laval官方社区主荐的一款鸿蒙开发主板。 该主板主要针对学生党&#xff0c;极客&#xff0c;工程师&#xff0c;极大降低了开源鸿蒙…

MEMS六轴陀螺仪工作原理介绍

MEMS&#xff08;微机电系统&#xff09;六轴陀螺仪主要包括三轴陀螺仪和三轴加速度计&#xff0c;以下是其工作原理的简要介绍&#xff1a; 三轴陀螺仪工作原理&#xff1a; 陀螺仪利用科里奥利力原理来测量角速度。它通常有一个可振动的质量…

VScode开发ARM环境搭建

1. vscode安装 直接访问官网: Visual Studio Code - Code Editing. Redefined 2. 安装插件 2.1. 安装Embedded IDE 2.2. 安装Cortex-debug 3. 工程初始化 3.1. 导入现有工程&#xff08;推荐&#xff09; 3.2. 或可创建新的工程 3.2.1. 选择Cortex-M项目 指定项目名称&…

一文简述AI自动化漏洞修复实践

2024年&#xff0c;人工智能&#xff08;AI&#xff09;技术正以其前所未有的速度和影响力&#xff0c;革新着网络安全领域。AI在自动化漏洞修复方面的应用&#xff0c;标志着我们迈入了一个全新的网络安全时代。近日&#xff0c;在中国电信组织的一场技术交流会上&#xff0c;…

【React】Axios请求头注入token

业务背景: Token作为用户的数据标识&#xff0c;在接口层面起到了接口权限控制的作用&#xff0c;也就是说后端有很多接口都需要通过查看当前请求头信息中是否含有token数据&#xff0c;来决定是否正常返回数据 // 添加请求拦截器 request.interceptors.request.use(config …

多模块开发

简介 Git 通过子模块来解决复用模块的问题。 submodule允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中&#xff0c;同时还保持提交的独立。而subtree可以将子模块合并到主模块由主模块完全管理。 git subModule Git地址&#…

【Kafka】Kafka生产者数据重复、数据有序、数据乱序-07

【Kafka】Kafka生产者数据重复、数据有序、数据乱序-07 1. 数据重复1.1 数据传递语义1.2 幂等性1.2.1 如何开启幂等性1.2.2 同一个消息&#xff0c;多个分区都会存在吗&#xff1f; 1.3 事务1.3.1 Kafka 事务原理1.3.2 Kafka事务的作用和意义作用具体应用场景 2. 数据有序3. 数…

Docker 部署项目,真的太雅了~

大家好&#xff0c;我是南城余&#xff01; 最近在找工作&#xff0c;正好手里有台服务器&#xff0c;之前项目上线用的宝塔部署项目上线&#xff0c;在公司实习了一年后&#xff0c;发现如今项目部署都使用的是容器化部署方案&#xff0c;也就是类似于和 Docker 一样的部署方案…

鸿蒙开发通信与连接:【@ohos.nfc.cardEmulation (标准NFC-cardEmulation)】

标准NFC-cardEmulation 本模块主要用于操作及管理NFC卡模拟。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import cardEmulation from ohos.nfc.cardEmulation;cardEmulation.is…

全网最易懂,开源时序数据库influxDB,实际应用评测

前言&#xff1a; 当今是信息爆炸的时代&#xff0c;在处理高频数据时&#xff0c;关系型数据库oracle/mysql明显表现出乏力&#xff0c;因秒级、毫秒级高频数据&#xff0c;分分钟可以把关系型数据库的表塞爆。在日常生活工作中&#xff0c;我们经常会遇到哪些需要高频分析的场…

NXP实战笔记(十四):32K3xx基于RTD-SDK在S32DS实现HSE的安装。

目录 1、概述 1.1、什么是HSE&#xff1f; 1.2、如何实现HSE的OTA功能 1.3、S32K3放置HSE的地址 2、通过调试器安装HSE 3、通过IVT方式安装HSE 4、坑点慎重踩 4.1、优化等级 4.2、Flash放RAM 4.3、C40_Ip配置更改 4.4、程序烧录 5、测试结果 6、代码链接 1、概述 首…