Springboot2.1.9+druid+mybatits(不重启项目动态添加mysql和oracle数据源)和数据监控

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: Springboot2.1.9+druid+mybatits(不重启项目动态添加mysql和oracle数据源)和数据监控

一、前言



最近公司来了一个项目,在理需求和编写接口文档的时候有一个比较有意思的需求:项目启动时不加载数据库,然后管理页面需要提供一个接口,用来配置数据库,配置成功后才连接数据库。于是我做了以下的尝试。


二、技术预研



1.我首先想到的是:不配置url


2019-11-22 16:16:27.268 ERROR 90476 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class


这里表示如果需要spring容器管理dataSource就必须在配置文件中配置一个数据源,但是与我的需求不符合,失败。


2.然后我就想如果我排除spring自动配置数据源


@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class,
                                  DataSourceAutoConfiguration.class})


但是这里也存在一个问题,通过自动装配实现的mapper无法被识别和实例化,需要自己全部接管所有的sqlBeanFactory,这简直是一个灾难,所以这个宣告失败。


3.使用sqlite数据库当做默认数据库,让springboot帮我自动装配,然后调用接口的时候把这个bean从容器中移除


sqlite是一个文件,可以放在项目中,不需要开启服务,连接就能用,很方便,这个宣告成功,实现代码如下。


三、实现思路



  1. 在启动方法处获取spring上下文
  2. 注入到SpringContextUtil中
  3. 通过@Bean注入MyDynamicDataSource配置到容器中,并设置默认的数据源
  4. 重写AbstractRoutingDataSource类的determineCurrentLookupKey方法,实现数据源的切换
  5. ThreadLocal 保证当前线程安全的前提下设置当前线程的数据源


四、代码实现



  1. 配置文件配置


server.port=8081
server.tomcat.uri-encoding=utf-8
#指定连接地址和数据库
spring.datasource.url=jdbc:sqlite:classpath:static/defaultDataBase/default.db
spring.datasource.driver-class-name=org.sqlite.JDBC
#指定数据源为druid
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 如果没有进行第三步3的配置,下面的属性是不会生效的
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=6000
spring.datasource.timeBetweenEvictionRunsMillis=6000
spring.datasource.minEvictableIdleTimeMillis=30000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
#filters=stat,wall,log4j
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.useGlobalDataSourceStat=true
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# 指定全局配置文件的位置
mybatis.config-location=classpath:mybatis-config.xml
# 指定sql映射文件的位置
mybatis.mapper-locations=classpath:mappers/*.xml


2.pom引入


<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.infosec</groupId>
    <artifactId>sra</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SRA</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!-- swagger -->
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.gizwits</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!-- 阿里连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mappers-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--ojdbc7驱动 -->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc7</artifactId>
            <version>12.1.0.2.2</version>
            <scope>system</scope>
            <systemPath>${pom.basedir}/src/main/resources/static/lib/ojdbc7-12.1.0.2.jar
            </systemPath>
        </dependency>
        <!--sqlite驱动-->
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.23.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


这里有一个问题如果druid版本太低会出现以下的异常,解决办法是提高版本


Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/autoconfigure/jdbc/metadata/DataSourcePoolMetadataProvider
 at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_201]
 at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_201]
 at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_201]


  1. druid配置类


package com.infosec.ra.configuration;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.infosec.ra.common.MyDynamicDataSource;
import com.infosec.ra.filter.SrmFilter;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Configuration
public class DruidConfig {
    /**
     * @return
     * @Bean 防止数据监控报错,无法查看数据源
     * @ConfigurationProperties 会把配置文件的参数自动赋值到dataSource里。
     * @Primary 用于标识默认使用的 DataSource Bean
     */
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    @Primary
    public DataSource masterDataSource() {
        log.info("创建masterDataSource");
        //DruidDataSource druidDataSource = new DruidDataSource();
        DruidDataSource druidDataSource = DruidDataSourceBuilder.create().build();
        return druidDataSource;
    }
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        MyDynamicDataSource myDynamicDataSource = new MyDynamicDataSource();
        // 配置多数据源
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource());
        myDynamicDataSource.setTargetDataSources(targetDataSources);
        return myDynamicDataSource;
    }
    /**
     * 配置 SqlSessionFactoryBean
     */
    @Bean(value = "sqlSessionFactoryBeanTest")
    @ConfigurationProperties(prefix = "mappers")
    public SqlSessionFactoryBean sqlSessionFactoryBean() {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 配置数据源,此处配置为关键配置,如果没有将 dynamicDataSource 作为数据源则不能实现切换
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        return sqlSessionFactoryBean;
    }
    /**
     * 注入 DataSourceTransactionManager 用于事务管理
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
    @Bean
    public ServletRegistrationBean statViewServlet() {
        //创建servlet注册实体
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        //设置ip白名单
        servletRegistrationBean.addInitParameter("allow", "");
        //设置ip黑名单
        servletRegistrationBean.addInitParameter("deny", "");
        //设置控制台管理用户__登录用户名和密码
        servletRegistrationBean.addInitParameter("loginUsername", "druid");
        servletRegistrationBean.addInitParameter("loginPassword", "123456");
        //是否可以重置数据
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }
    /**
     * druid过滤器
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean druidFilter() {
        //创建过滤器
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        //设置过滤器过滤路径
        filterRegistrationBean.addUrlPatterns("/*");
        //忽略过滤的形式
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}


  1. 启动类


我这里是在windows开发,然后正式环境在linux上的,所以为了避免频繁修改配置文件,我通过System类获取操作系统类型,判断是开发还是正式环境,自动切换配置文件。


package com.infosec.ra;
import com.infosec.ra.util.DataSourceUtil;
import com.infosec.ra.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Map;
@Slf4j
@SpringBootApplication
public class SraApplication extends SpringBootServletInitializer {
    //环境变量OS对应操作系统
    private static final String OS = "OS";
    //项目所处操作系统环境为windows
    private static final String WINDOWS = "Windows";
    //项目为开发环境
    private static final String DEVELOP = "develop";
    //项目为测试环境
    private static final String PRODUCT = "product";
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SraApplication.class).profiles(getProfile());
    }
    private static String getProfile(){
        //获取系统环境变量
        Map<String, String> env = System.getenv();
        //获取操作系统类型,支持windows和linux
        String profile = (env != null && env.get(OS).contains(WINDOWS) ? DEVELOP : PRODUCT);
        return profile;
    }
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder().sources(SraApplication.class).profiles(getProfile()).run(args);
        log.info("SpringBoot启动成功");
        SpringContextUtil.setApplicationContext(applicationContext);
        DataSourceUtil.initDataSource();
    }
}


5.数据源工具类


package com.infosec.ra.util;
import com.alibaba.druid.pool.DruidDataSource;
import com.infosec.ra.common.MyDynamicDataSource;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
 * 初始化和添加数据源
 */
@Slf4j
public class DataSourceUtil {
    public static final Map<Object, Object> dataSourceMap = new HashMap<>();
    public static void initDataSource() {
        //获取masterDataSource
        DruidDataSource masterDataSource = (DruidDataSource) SpringContextUtil.getBean("masterDataSource");
        addDataSource("master", masterDataSource);
        //初始化其它数据源
        //initOthersDataSource();
        //刷新数据源
        flushDataSource();
    }
    public static void flushDataSource() {
        //获取spring管理的dynamicDataSource
        MyDynamicDataSource myDynamicDataSource = (MyDynamicDataSource) SpringContextUtil.getBean("dynamicDataSource");
        //将数据源设置到 targetDataSources
        myDynamicDataSource.setTargetDataSources(dataSourceMap);
        //将 targetDataSources 中的连接信息放入 resolvedDataSources 管理
        myDynamicDataSource.afterPropertiesSet();
    }
    public static void addDataSource(String key, DruidDataSource masterDataSource) {
        dataSourceMap.put(key, masterDataSource);
    }
    private static void initOthersDataSource() {
        //在此处可以查询出所有的数据源(例如,配置文件,数据库)然后添加
        String key = "slave";
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("123456");
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://10.100.61.160:3306/db1");
        //添加数据源到map
        addDataSource(key, druidDataSource);
    }
}


  1. spring上下文工具类


package com.infosec.ra.util;
import org.springframework.context.ApplicationContext;
public class SpringContextUtil {
    private static ApplicationContext applicationContext;
    //获取上下文
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    //设置上下文
    public static void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextUtil.applicationContext = applicationContext;
    }
    //通过名字获取上下文中的bean
    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
    //通过类型获取上下文中的bean
    public static Object getBean(Class<?> requiredType) {
        return applicationContext.getBean(requiredType);
    }
}
  1. 动态数据源MyDynamicDataSource
package com.infosec.ra.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.StringUtils;
@Slf4j
public class MyDynamicDataSource extends AbstractRoutingDataSource {
    @Override
    public Object determineCurrentLookupKey() {
        //获取当前线程的数据源,如果不存在使用master数据源
        String datasource = DBContextHolder.getDataSource();
        if (StringUtils.isEmpty(datasource)) {
            datasource = "master";
        }
        logger.info("datasource=" + datasource);
        return datasource;
    }
}


8.数据源切换类


package com.infosec.ra.common;
import com.infosec.ra.util.DataSourceUtil;
public class DBContextHolder {
    // 对当前线程的操作-线程安全的
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    // 调用此方法,切换数据源
    public static void setDataSource(String dataSource) {
        if (DataSourceUtil.dataSourceMap.containsKey(dataSource)) {
            contextHolder.set(dataSource);
        } else {
            throw new RuntimeException("数据源:" + dataSource + "不存在");
        }
    }
    // 获取数据源
    public static String getDataSource() {
        return contextHolder.get();
    }
    // 删除数据源
    public static void clearDataSource() {
        contextHolder.remove();
    }
}


9.mapper类


package com.infosec.ra.mapper;
import com.infosec.ra.entity.Role;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface RoleMapper {
    @Select("select * from ROLE")
    List<Role> getRoles();
}


10.controller类


package com.infosec.ra.controller;
import com.alibaba.druid.pool.DruidDataSource;
import com.infosec.ra.common.DBContextHolder;
import com.infosec.ra.entity.Role;
import com.infosec.ra.mapper.RoleMapper;
import com.infosec.ra.util.DataSourceUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
@RestController
public class DataSourceController {
    @Autowired
    private RoleMapper roleMapper;
    @GetMapping("/role")
    public List<Role> getRoles(){
        //double random = Math.random();
        /*if((random*10)%2==0){
            DBContextHolder.setDataSource("master");
        }else{
            DBContextHolder.setDataSource("slave2");
        }*/
        DBContextHolder.setDataSource("master");
        return roleMapper.getRoles();
    }
    @GetMapping("/roles")
    public List<Role> getRoless(){
        DBContextHolder.setDataSource("slave2");
        return roleMapper.getRoles();
    }
    @PostMapping("/test")
    public String addDataSource(String token,String userName,String password,String driver,String url,String key){
        Map<String, String> map = new HashMap<>();
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername(userName);
        druidDataSource.setPassword(password);
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        //添加数据源到map
         DataSourceUtil.addDataSource(key, druidDataSource);
        // 刷新
        DataSourceUtil.flushDataSource();
        map.put("msg", "数据源数量:" + DataSourceUtil.dataSourceMap.size());
        return "添加成功:"+DataSourceUtil.dataSourceMap.size();
    }
}


五、结果展示



  1. 刚启动,前端没有配置数据源,所以看不到数据源



在这里插入图片描述


2.通过swagger调用接口,配置数据源


再加一个mybatits数据库


userName: root
pwd: 123456
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://10.100.61.160:3306/db1
key: master


  1. 再次查看数据源,可以在数据源中找到两个,一个是mysql,一个是oracle


640.png

在这里插入图片描述


  1. 查询结果


#mysql
[
  {
    "id": 1,
    "name": "test"
  }
]
#oracle
[
  {
    "id": 1,
    "name": "安全管理员"
  },
  {
    "id": 2,
    "name": "系统管理员"
  },
  {
    "id": 3,
    "name": "日志管理员"
  }
]


这里需要先执行查询方法,然后在数据源中才能看到刚刚添加的数据源,如果碰到问题,欢迎提问!


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
113 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
7天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
39 14
|
10天前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
39 9
|
15天前
|
存储 easyexcel Java
SpringBoot+EasyExcel轻松实现300万数据快速导出!
本文介绍了在项目开发中使用Apache POI进行数据导入导出的常见问题及解决方案。首先比较了HSSFWorkbook、XSSFWorkbook和SXSSFWorkbook三种传统POI版本的优缺点,然后根据数据量大小推荐了合适的使用场景。接着重点介绍了如何使用EasyExcel处理超百万数据的导入导出,包括分批查询、分批写入Excel、分批插入数据库等技术细节。通过测试,300万数据的导出用时约2分15秒,导入用时约91秒,展示了高效的数据处理能力。最后总结了公司现有做法的不足,并提出了改进方向。
|
21天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
18天前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
38 1
|
19天前
|
SQL 关系型数据库 MySQL
mysql数据误删后的数据回滚
【11月更文挑战第1天】本文介绍了四种恢复误删数据的方法:1. 使用事务回滚,通过 `pymysql` 库在 Python 中实现;2. 使用备份恢复,通过 `mysqldump` 命令备份和恢复数据;3. 使用二进制日志恢复,通过 `mysqlbinlog` 工具恢复特定位置的事件;4. 使用延迟复制从副本恢复,通过停止和重启从库复制来恢复数据。每种方法都有详细的步骤和示例代码。
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
143 1
|
17天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
95 62
|
15天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
34 2

推荐镜像

更多