SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(多数据源配置)

news2024/10/10 6:57:27

SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(多数据源配置)

  • 前言
  • 多数据源配置
    • 引入aop依赖
    • 1. properties配置多数据源
    • 2. 创建数据源枚举类
    • 3. 线程参数配置类
    • 4. 数据源动态切换类
    • 5. 多数据源配置类
      • HikariCP 版本
      • Druid 版本
    • 6. 自定义多数据源切换注解
    • 7. 数据源注解截面AOP
    • 8. 测试 多数据源 是否起效

前言

我这边的SpringBoot的版本为2.6.13,其中Quartz是使用的以下方式引入

<!--quartz定时任务-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

由于我目前需要使用@QuartzDataSource去指定数据源,所以就不通过@DS注解去实现多数据源
而是通过自定义DynamicDataSource 去实现了多数据源

多数据源配置

引入aop依赖

<!--spring切面aop依赖-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1. properties配置多数据源

# 应用服务 WEB 访问端口
server.port=9081

# 主数据源
spring.datasource.db1.url=jdbc:mysql://localhost:3306/sharding?useSSL=false&serverTimezone=UTC
spring.datasource.db1.jdbc-url=jdbc:mysql://localhost:3306/sharding?useSSL=false&serverTimezone=UTC
spring.datasource.db1.username=root
spring.datasource.db1.password=root
spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver

# 次数据源
spring.datasource.db2.url=jdbc:mysql://localhost:3306/sharding?useSSL=false&serverTimezone=UTC
spring.datasource.db2.jdbc-url=jdbc:mysql://localhost:3306/sharding?useSSL=false&serverTimezone=UTC
spring.datasource.db2.username=root
spring.datasource.db2.password=root
spring.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver

# quartz 数据源
#spring.datasource.task.url=jdbc:mysql://localhost:3306/quartz
spring.datasource.task.jdbc-url=jdbc:mysql://localhost:3306/quartz
spring.datasource.task.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.task.username=root
spring.datasource.task.password=root

# Quartz Scheduler 配置
# 指定作业存储类型为JDBC,使用数据库来存储作业和调度信息
spring.quartz.job-store-type=jdbc
# 在关闭时等待作业完成
spring.quartz.wait-for-jobs-to-complete-on-shutdown=true
# 不初始化数据库架构,假设数据库架构已经存在
spring.quartz.jdbc.initialize-schema=never
# Quartz Scheduler 属性配置
spring.quartz.properties.org.quartz.jobStore.dataSource=quartz_jobs
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
# 启用集群模式
spring.quartz.properties.org.quartz.jobStore.isClustered=true
# 集群检查间隔时间(毫秒)
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=1000
# 不使用属性来存储作业数据,改为使用BLOB字段
spring.quartz.properties.org.quartz.jobStore.useProperties=false
# 指定作业存储的类,这里使用Spring提供的LocalDataSourceJobStore,但通常这个配置是隐式的,
# 除非你有特殊的实现需求,否则通常不需要显式设置这个属性。
# spring.quartz.properties.org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore
# 注意:上面的行已被注释掉,因为通常不需要显式设置
# 调度器实例名称和ID(org.quartz.scheduler.instanceName 这个是保证属于同一个集群)
spring.quartz.properties.org.quartz.scheduler.instanceName=SC_Scheduler
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
# 线程池配置
# 线程池中线程的数量
spring.quartz.properties.org.quartz.threadPool.threadCount=25
# 线程优先级
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
# 线程池实现类
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool

2. 创建数据源枚举类

package com.example.springbootfull.quartztest.enums;

/**
 * 数据源
 */
public enum DataSourceType {
    /**
     * 数据源1
     * */
    DB1,

    /**
     * 数据源2
     * */
    DB2
}

3. 线程参数配置类

定义一个工具类来设置当前线程的数据源枚举值

package com.example.springbootfull.quartztest.datasource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 数据源切换处理
 */
public class DynamicDataSourceContextHolder {
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源的变量
     */
    public static void setDataSourceType(String dsType) {
        log.info("切换到{}数据源", dsType);
        CONTEXT_HOLDER.set(dsType);
    }

    /**
     * 获得数据源的变量
     */
    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清空数据源变量
     */
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}

4. 数据源动态切换类

package com.example.springbootfull.quartztest.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;



/**
 * Spring的AbstractRoutingDataSource抽象类,实现动态数据源(他的作用就是动态切换数据源)
 * AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心,
 * 这里对该方法进行Override。【上下文DynamicDataSourceContextHolder为一线程安全的ThreadLocal】
 */
public class DynamicDataSource extends AbstractRoutingDataSource {


    /**
     * 取得当前使用哪个数据源
     * @return dbTypeEnum
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

5. 多数据源配置类

HikariCP 版本

package com.example.springbootfull.quartztest.config;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.example.springbootfull.quartztest.datasource.DynamicDataSource;
import com.example.springbootfull.quartztest.enums.DataSourceType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 多数据源配置
 */
@Configuration
public class DataSourceConfig {

    /**
     * 创建第一个数据源
     *
     * @return dataSource
     */
    @Bean(name = "dataSource1")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建第二个数据源
     *
     * @return dataSource
     */
    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

    //quartz数据库 dataSourceTask数据源
    //使用@QuartzDataSource后,不需要动态配置
    @Bean(name = "dataSourceTask")
    @ConfigurationProperties(prefix = "spring.datasource.task")
    @QuartzDataSource
    public DataSource dataSourceTask() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 动态数据源配置
     *
     * @return dataSource
     */
    @Primary
    @Bean("multipleDataSource")
    public DataSource multipleDataSource(@Qualifier("dataSource1") DataSource db1,
                                         @Qualifier("dataSource2") DataSource db2) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> dataSources = new HashMap<>();
        dataSources.put(DataSourceType.DB1, db1);
        dataSources.put(DataSourceType.DB2, db2);
        dynamicDataSource.setTargetDataSources(dataSources);
        //默认数据源
        dynamicDataSource.setDefaultTargetDataSource(db1);
        return dynamicDataSource;
    }

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("multipleDataSource") DataSource multipleDataSource) throws Exception {
        // 导入mybatissqlsession配置
        MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
        // 指明数据源
        sessionFactory.setDataSource(multipleDataSource);
        // 设置mapper.xml的位置路径
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/**/*.xml");
        sessionFactory.setMapperLocations(resources);
        //指明实体扫描(多个package用逗号或者分号分隔)
        //sessionFactory.setTypeAliasesPackage("com.szylt.projects.project.entity");
        // 导入mybatis配置
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sessionFactory.setConfiguration(configuration);
        return sessionFactory.getObject();
    }


    //数据源事务配置
    @Bean
    public PlatformTransactionManager transactionManager(DataSource multipleDataSource) {
        return new DataSourceTransactionManager(multipleDataSource);
    }

}

Druid 版本

需要先引入 Druid 依赖,这里使用的是 Druid 官方的 Starter

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.2.8</version>
</dependency>

然后,在properties配置文件中 为每个数据源配置DruidDataSour数据库连接池

spring.datasource.db1.type=com.alibaba.druid.pool.DruidDataSour
spring.datasource.db2.type=com.alibaba.druid.pool.DruidDataSour
spring.datasource.task.type=com.alibaba.druid.pool.DruidDataSour

接着把一下DataSourceConfig 类里面的
DataSource 对象 换成 DruidDataSource 对象
DataSourceBuilder 对象 换成 DruidDataSourceBuilder 对象
就好了

6. 自定义多数据源切换注解

package com.example.springbootfull.quartztest.annotation;

import com.example.springbootfull.quartztest.enums.DataSourceType;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义多数据源切换注解
 * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource
{
    /**
     * 切换数据源名称
     */
    public DataSourceType value() default DataSourceType.DB1;
}

7. 数据源注解截面AOP

package com.example.springbootfull.quartztest.aspectj;

import java.util.Objects;

import com.example.springbootfull.quartztest.annotation.DataSource;
import com.example.springbootfull.quartztest.datasource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


/**
 * 多数据源处理
 *
 */
@Aspect
@Order(1)
@Component
public class DataSourceAspect {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(com.example.springbootfull.quartztest.annotation.DataSource)"
            + "|| @within(com.example.springbootfull.quartztest.annotation.DataSource)")
    public void dsPointCut() {

    }

    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        DataSource dataSource = getDataSource(point);
        if (dataSource != null) {
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
        }
        try {
            return point.proceed();
        } finally {
            // 销毁数据源 在执行方法之后
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }

    /**
     * 获取需要切换的数据源
     */
    public DataSource getDataSource(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
        if (Objects.nonNull(dataSource)) {
            return dataSource;
        }

        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
    }
}

8. 测试 多数据源 是否起效

创建了一个控制层测试类

package com.example.springbootfull.mybatisplustest.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springbootfull.mybatisplustest.entity.SysUser;
import com.example.springbootfull.mybatisplustest.mapper.SysUserMapper;
import com.example.springbootfull.quartztest.annotation.DataSource;
import com.example.springbootfull.quartztest.enums.DataSourceType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author jiang
 * @since 2024-09-13
 */
@Controller
@RequestMapping("/mybatisplustest/sysUser")
public class SysUserController {

    @Autowired
    private SysUserMapper sysUserMapper;

    @RequestMapping("/selectAll")
    @DataSource(value = DataSourceType.DB1)
    public void contextLoads() {
        //第一页,10个
        Page<SysUser> page = new Page<>(1, 10);
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        //查询liek人1的
        //wrapper.eq("enabled", true).like("account", "小明机器人10号");
        //查询授权=true的;
        wrapper.like("account", "人1");
        IPage<SysUser> iPage = sysUserMapper.selectPage(page, wrapper);

        //总页数
        System.out.println("总页数:"+iPage.getPages());
        //总条数
        System.out.println("总条数:"+iPage.getTotal());
        //每页条数
        System.out.println("每页条数:"+iPage.getSize());
        //当前页的结果集
        System.out.println("当前页的结果集:"+iPage.getRecords());
        //当前页号
        System.out.println("当前页号:"+iPage.getCurrent());

//        // 创建实体类
//        SysUser sysUser = new SysUser();
//        sysUser.setAccount("mybtis呀");
//        sysUser.setEnabled(Boolean.TRUE);
//        sysUser.setCreateAt(new Date());
//        sysUserDao.insertSelective(sysUser);
//
//        // 根据自增ID检索实体
//        SysUser sysUser1 = sysUserDao.selectByPrimaryKey(sysUser.getId());

//        logger.info("user={}", sysUser1);
    }

}

运行如下截图:
两者都有触发
在这里插入图片描述
参考文章如下:
【1】Springboot+Mybatis+MySql整合多数据源及其使用
【2】Springboot定时任务quartz整合(多数据源+quartz持久化到数据库)
【3】springboot+MybatisPlus+HikariCP多数据源动态配置(实战篇)
【4】springboot+mybatis-plus+quartz多数据源操作,亲测可用

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JS】用哈希法得到四数相加元组数

思路 根据题目这里是四个数组abcd的数相加&#xff0c;将数组两两分组&#xff0c;A大组为ab&#xff0c;B大组为cd由abcd0可得AB0&#xff0c;即B0-A遍历数组分别计算出AB大组所有sum值&#xff0c;先将A组sum值存进map里&#xff0c;再从map里面寻找有count个合适的B值&#…

Python in Excel 正式发布!

Excel 中的 Python 现已正式发布&#xff0c;适用于 Microsoft 365 商业版和企业版的 Windows 用户。去年 8 月&#xff0c;微软与 Anaconda 合作&#xff0c;通过集成 Python 为 Excel 引入了一个令人兴奋的新增功能&#xff0c;从而可以将 Python 和 Excel 分析无缝结合到同一…

使用npm i报错node-sass失败问题解决

node 版本&#xff1a;v14.15.4 解决方法&#xff1a; npm config set sass_binary_sitehttps://npmmirror.com/mirrors/node-sass设置完之后&#xff0c;再npm i 就可以下载成功 亲测有效

MySQL--视图(详解)

目录 一、前言二、视图2.1概念2.2语法2.3创建视图2.3.1目的 2.4查看视图2.5修改数据2.5.1通过真实表修改数据&#xff0c;会影响视图2.5.2通过修改视图&#xff0c;会影响基表 2.6注意2.7 删除视图2.8 视图的优点 一、前言 欢迎大家来到权权的博客~欢迎大家对我的博客进行指导&…

历时一个多月,搭建了一款培训考试小程序系统

前不久&#xff0c;一位在机构单位工作的朋友联系到我&#xff0c;说他们需要搭建一款内部培训考试系统&#xff0c;是关于安全知识学习与考试的。 此处省略好多张聊天页...... 为此&#xff0c;针对用户的需求&#xff0c;在搭建前&#xff0c;我做了大量的竞品分析&#xff…

探索 MicroRabbit:Python 中的通信新纪元

文章目录 探索 MicroRabbit&#xff1a;Python 中的通信新纪元背景&#xff1a;为什么选择 MicroRabbit&#xff1f;MicroRabbit 是什么&#xff1f;如何安装 MicroRabbit&#xff1f;简单的库函数使用方法场景应用示例常见 Bug 及解决方案总结 探索 MicroRabbit&#xff1a;Py…

计算机毕业设计 基于Python的智能停车管理系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

UML/SysML建模工具更新情况(2024年10月)(1)Rhapsody 10.0.1

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 工具最新版本&#xff1a;SinelaboreRT 6.4 更新时间&#xff1a;2024年9月23日 工具简介 状态机图和活动图代码生成工具。先在EA、Visual Paradigm 、Cadifra、UModel、MagicDraw、…

衡石分析平台系统管理手册-智能运维之系统设置

系统设置​ HENGSHI 系统设置中展示了系统运行时的一些参数&#xff0c;包括主程序相关信息&#xff0c;Base URL、HTTP 代理、图表数据缓存周期、数据集缓存大小、租户引擎等相关信息。 主程序​ 系统设置中展示了主程序相关信息&#xff0c;这些信息是系统自动生成的&#…

AOC商用显示器助力智能制造,赋能数智化发展!

摘要&#xff1a;为制造型企业向数字化、智能化转型提供有力助益&#xff01; 当今时代&#xff0c;我国制造业呈现出蓬勃发展之势。其中&#xff0c;显示器作为信息呈现的关键载体&#xff0c;其在制造业智能化进程中愈发发挥着重要作用&#xff0c;有助于实时、准确地展示生…

Mysql数据库安装与C++配置

本文档旨在为需要安装和配置MySQL 8.3、MySQL Workbench以及C Connector的用户提供详细的步骤指导。在安装过程中&#xff0c;可能会遇到一些常见问题&#xff0c;如DLL文件缺失等&#xff0c;本指南也会提供相应的解决办法。 1.安装Mysql8.3 安装Mysql有很多教程&#xff0c…

体感魂斗罗(二)姿势/手势与键位

文章目录 姿势/手势与键位映射 姿势/手势与键位映射 姿势/手势与键位映射暂时定为如下表的映射&#xff0c;搞出来一版&#xff0c;后续再优化 姿势/手势键位手掌上抬键位-上手掌下压键位-下手掌左挥键位-左手掌右挥键位-右挥拳A键抬腿B键OK手势暂停-开始

105. 从前序与中序遍历序列构造二叉树【 力扣(LeetCode) 】

文章目录 零、LeetCode 原题一、题目描述二、测试用例三、解题思路四、参考代码 零、LeetCode 原题 105. 从前序与中序遍历序列构造二叉树 一、题目描述 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的…

『网络游戏』客户端使用PESorket发送消息到服务器【14】

上一章服务器已经完成使用PESorket 现在我们将其导出在客户端中使用 生成成功后复制 粘贴到Unity项目中 进入Assets文件夹 粘贴两个.dll 创建脚本:ClientSession.cs 编写脚本: ClientSession.cs 编写脚本:GameStart.cs 将GameStart.cs脚本绑定在摄像机上 运行服务器 运行客户端…

【python实操】python小程序之封装(家具管理)

引言 python小程序之封装&#xff08;家具管理&#xff09; 文章目录 引言一、封装&#xff08;家具管理&#xff09;1.1 题目1.2 代码1.3 代码解释1.3.1 类 HouseItem1.3.2 类 House1.3.3 实例化与调用1.3.4 运行结果 四、思考 一、封装&#xff08;家具管理&#xff09; 1.1…

基于IDEA+SpringBoot+Vue+Uniapp的投票评选小程序系统的详细设计和实现

2. 详细视频演示 文章底部名片&#xff0c;联系我获取更详细的演示视频 3. 论文参考 4. 项目运行截图 代码运行效果图 代码运行效果图 代码运行效果图 代码运行效果图 代码运行效果图 5. 技术框架 5.1 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框…

令牌桶算法自学笔记

令牌桶算法可以处理大流浪场景。 令牌以恒定的速率向一个令牌通中放入令牌&#xff0c;每一个请求必须要从桶中拿到令牌&#xff0c;才可以完成后续处理请求的操作。如果一个请求没有拿到令牌&#xff0c;那么就解决请求。 可以处理固定桶数量的请求&#xff0c;当请求数量超…

【hot100-java】二叉树展开为链表

二叉树篇。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

进阶功法:SQL 优化指南

目录标题 SQL 优化指南1. 插入数据优化1.1 批量插入数据1.2 手动提交事务1.3 主键顺序插入1.4 大批量插入数据步骤&#xff1a; 2. 主键优化主键设计原则拓展知识 3. ORDER BY 优化3.1 Using filesort3.2 Using index示例 3.3 ORDER BY 优化原则 4. GROUP BY 优化示例 4.1 GROU…

社工字典生成工具 —— CeWL 使用手册

GitHub - digininja/CeWL: CeWL is a Custom Word List GeneratorCeWL is a Custom Word List Generator. Contribute to digininja/CeWL development by creating an account on GitHub.https://github.com/digininja/CeWL/ 0x01&#xff1a;CeWL 简介 CeWL&#xff08;Cust…