当前位置: 首页 > news >正文

spring boot 八、 sharding-jdbc 分库分表 按月分表

在项目resources目录下新建com.jianmu.config.sharding.DateShardingAlgorithm 文件

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

新增yaml配置 数据源

spring:shardingsphere:props:sql:#是否在日志中打印 SQLshow: true#打印简单风格的 SQLsimple: truedatasource:names: pingxuanlogpingxuanlog:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_jianmu_pingxuan_log?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8username: rootpassword: root#最大连接池数量max-active: 10#最小连接池数量min-idle: 5#初始化时建立物理连接的个数initial-size: 5#获取连接时最大等待时间,单位毫秒max-wait: 3000#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒time-between-eviction-runs-millis: 60000#配置一个连接在池中最小生存的时间,单位是毫秒min-evictable-idle-time-millis: 100000#用来检测连接是否有效的sql,要求是一个查询语句validation-query: SELECT 1 FROM DUAL#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true

新增yaml配置 sharding 分表规则

spring:shardingsphere:sharding:tables:t_act_vt_log:#配置数据节点,这里是按月分表,时间范围设置在202201 ~ 210012actual-data-nodes: pingxuanlog.t_act_vt_log_$->{202201..203012}table-strategy:standard:#使用标准分片策略,配置分片字段sharding-column: add_time# 精确匹配规则(自定义类)precise-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithm# 范围匹配规则(自定义类)range-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithmt_act_access_log:#配置数据节点,这里是按月分表,时间范围设置在202201 ~ 210012actual-data-nodes: pingxuanlog.t_act_access_log_$->{202201..203012}table-strategy:standard:#使用标准分片策略,配置分片字段sharding-column: add_time# 精确匹配规则(自定义类)precise-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithm# 范围匹配规则(自定义类)range-algorithm-class-name: com.jianmu.config.sharding.DateShardingAlgorithm

DataSourceConfiguration

package com.jianmu.config.sharding;import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.util.Map;/*** 动态数据源配置:* <p>* 使用{@link com.baomidou.dynamic.datasource.annotation.DS}注解,切换数据源** <code>@DS(DataSourceConfiguration.SHARDING_DATA_SOURCE_NAME)</code>**/
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DataSourceConfiguration {/*** 分表数据源名称*/public static final String SHARDING_DATA_SOURCE_NAME = "sharding";/*** 动态数据源配置项*/private final DynamicDataSourceProperties dynamicDataSourceProperties;private final ShardingDataSource shardingDataSource;@Autowiredpublic DataSourceConfiguration(DynamicDataSourceProperties dynamicDataSourceProperties, @Lazy ShardingDataSource shardingDataSource) {this.dynamicDataSourceProperties = dynamicDataSourceProperties;this.shardingDataSource = shardingDataSource;}/*** 将shardingDataSource放到了多数据源(dataSourceMap)中**/@Beanpublic DynamicDataSourceProvider dynamicDataSourceProvider() {Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();return new AbstractDataSourceProvider() {@Overridepublic Map<String, DataSource> loadDataSources() {Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);// 将 sharding jdbc 管理的数据源也交给动态数据源管理dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource);return dataSourceMap;}};}/*** 将动态数据源设置为首选的* 当spring存在多个数据源时, 自动注入的是首选的对象* 设置为主要的数据源之后,就可以支持sharding jdbc原生的配置方式*/@Primary@Beanpublic DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());dataSource.setStrict(dynamicDataSourceProperties.getStrict());dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());dataSource.setProvider(dynamicDataSourceProvider);dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());dataSource.setSeata(dynamicDataSourceProperties.getSeata());return dataSource;}
}
package com.jianmu.config.sharding;import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;import javax.sql.DataSource;
import java.util.Map;/*** @author kong*/
@Configuration
public class DataSourceHealthConfig extends DataSourceHealthContributorAutoConfiguration {@Value("${spring.datasource.dbcp2.validation-query:select 1}")private String defaultQuery;public DataSourceHealthConfig(Map<String, DataSource> dataSources, ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {super(dataSources, metadataProviders);}@Overrideprotected AbstractHealthIndicator createIndicator(DataSource source) {DataSourceHealthIndicator indicator = (DataSourceHealthIndicator) super.createIndicator(source);if (!StringUtils.hasText(indicator.getQuery())) {indicator.setQuery(defaultQuery);}return indicator;}
}
package com.jianmu.config.sharding;import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.jianmu.tools.ApplicationContextTools;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;/**sharding  分库分表策略配置:按照年月 如t_act_vt_log_202208**/
@Slf4j
public class DateShardingAlgorithm implements PreciseShardingAlgorithm<LocalDateTime>, RangeShardingAlgorithm<LocalDateTime> {private final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMM");@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<LocalDateTime> psv) {final String table = psv.getLogicTableName();final String prefix = table + "_";if (log.isDebugEnabled()) {log.debug("分表更新");}TableService tableService = (TableService) ApplicationContextTools.getBean(TableService.class);//添加日期final String logicTable = prefix + psv.getValue().format(this.format);boolean exist = tableService.exist(logicTable);if (log.isDebugEnabled()) {log.debug("更新: {} 存在:{}", logicTable, exist);}//匹配到了if (exist) {return logicTable;}//未匹配到if (log.isDebugEnabled()) {log.debug("sharding 未匹配到表,需要创建");}//创建这张表tableService.copy(logicTable, table);return logicTable;}/*** 范围匹配*/@SneakyThrows@Overridepublic Collection<String> doSharding(Collection<String> collection, RangeShardingValue<LocalDateTime> rsv) {final String table = rsv.getLogicTableName();final String prefix = table + "_";if (log.isDebugEnabled()) {log.debug("分表查询 表:{}", table);}TableService tableService = (TableService) ApplicationContextTools.getBean(TableService.class);List<String> tables = tableService.tables();Range<LocalDateTime> range = rsv.getValueRange();//计算出时间范围内的所有日期final int upper = range.hasUpperBound() ? Integer.parseInt(range.upperEndpoint().toLocalDate().format(this.format)) : 0;final int lower = range.hasLowerBound() ? Integer.parseInt(range.lowerEndpoint().toLocalDate().format(this.format)) : 0;List<String> validTables = this.validTables(prefix, tables, upper, lower);if (log.isDebugEnabled()) {log.debug("查询表:{}", JSON.toJSONString(validTables));}if (CollectionUtils.isEmpty(validTables)) {if (log.isDebugEnabled()) {log.debug("查询表不存在 改查原始表");}return Lists.newArrayList(table);}return validTables;}private List<String> validTables(String prefix, List<String> tables, int upper, int lower) {if (log.isDebugEnabled()) {log.debug("上界:{},下界:{}", upper, lower);}return tables.parallelStream().filter(i -> {if (i.contains(prefix)) {final String date = i.replace(prefix, "");if (date.matches("[0-9]*")) {final int mouth = Integer.parseInt(date);if (upper > 0 && lower > 0) {return mouth <= upper && mouth >= lower;} else {if (upper > 0) {return mouth <= upper;}if (lower > 0) {return mouth >= lower;}}}}return false;}).collect(Collectors.toList());}}
package com.jianmu.config.sharding;public class ShardingConstant {public static final String ORIGINAL_DATABASE = "db_jianmu_pingxuan_log";
}
package com.jianmu.config.sharding;import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.ExecutionException;public interface TableService {/*** 返回所有表*/List<String> tables() throws ExecutionException, SQLException;boolean exist(String table);/*** 精确删除表*/boolean drop(String table);/*** 旧表复制为新表*/boolean copy(String newTable, String usedTable);
}
package com.jianmu.config.sharding;import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.jianmu.constant.SysRedisConstant;
import com.jianmu.mapper.system.TableMapper;
import com.jianmu.tools.JdbcTools;
import com.jianmu.tools.log.LogTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;import java.sql.SQLException;
import java.util.List;@Slf4j
@Service
@DS("sharding")
public class TableServiceImpl implements TableService {private final TableMapper tableMapper;private final RedisTemplate<String, Object> redis;private final ValueOperations<String, Object> redisValue;private final DynamicRoutingDataSource dynamicRoutingDataSource;@Autowiredpublic TableServiceImpl(TableMapper tableMapper, RedisTemplate<String, Object> redis, DynamicRoutingDataSource dynamicRoutingDataSource) {this.tableMapper = tableMapper;this.redis = redis;this.redisValue = redis.opsForValue();this.dynamicRoutingDataSource = dynamicRoutingDataSource;}@Overridepublic List<String> tables() throws SQLException {List<String> tables = (List<String>) this.redisValue.get(SysRedisConstant.TABLES);if (tables == null) {List<String> list = JdbcTools.tables(this.dynamicRoutingDataSource.getDataSource(DataSourceConfiguration.SHARDING_DATA_SOURCE_NAME).getConnection(), ShardingConstant.ORIGINAL_DATABASE);//每24小时更新一次this.redisValue.set(SysRedisConstant.TABLES, list, 86400);return list;}return tables;}@Overridepublic boolean exist(String table) {try {Integer exist = this.tableMapper.exist(table);if (log.isDebugEnabled()) {log.debug("表:{} 存在:{}", table, exist);}return true;} catch (Exception e) {LogTools.err(e);return false;}}@Overridepublic boolean drop(String table) {boolean flag = this.tableMapper.drop(table) >= 0;if (flag) {this.delCache();}return flag;}@Overridepublic boolean copy(String newTable, String usedTable) {boolean flag = this.tableMapper.copy(newTable, usedTable) >= 0;if (flag) {this.delCache();}return flag;}private void delCache() {this.redis.delete(SysRedisConstant.TABLES);}}

t_act_vt_log 为每次自动生成的基础表 需要在这个表建好索引等

在这里插入图片描述

相关文章:

spring boot 八、 sharding-jdbc 分库分表 按月分表

在项目resources目录下新建com.jianmu.config.sharding.DateShardingAlgorithm 文件 新增yaml配置 数据源 spring:shardingsphere:props:sql:#是否在日志中打印 SQLshow: true#打印简单风格的 SQLsimple: truedatasource:names: pingxuanlogpingxuanlog:type: com.alibaba.dru…...

Java 8 中Stream流的一些用法

public class Djmxlist {private String dxmc;private Integer sl;public String getDxmc() {return dxmc;}public void setDxmc(String dxmc) {this.dxmc dxmc;}public Integer getSl() {return sl;}public void setSl(Integer sl) {this.sl sl;} }插入一下数据 List<Djm…...

Elasticsearch 8.10 中引入查询规则 - query rules

作者&#xff1a;Kathleen DeRusso 我们很高兴宣布 Elasticsearch 8.10 中的查询规则&#xff01; 查询规则&#xff08;query rules&#xff09;允许你根据正在搜索的查询词或根据作为搜索查询的一部分提供的上下文信息来更改查询。 什么是查询规则&#xff1f; 查询规则&…...

Windows PostgreSql 创建多个数据库目录

1 使用默认用户Administrator 1.1初始化数据库目录 E:\Program Files\PostgreSQL\13> .\bin\initdb -D G:\DATA\pgsql\data3 -W -A md5 1.2连接数据库 这时User为Administrator&#xff0c;密码就是你刚才设置的&#xff0c;我设置的为123456&#xff0c;方便测试。 2 添加…...

Java AOP Framework概述

Java AOP Framework概述 1. AspectJ1.1 使用AspectJ进行切面编程 2. Spring AOP2.1 使用Spring AOP进行切面编程2.2 如何决定使用哪种动态代理2.3 如何通过配置指定代理方式2.4 Spring AOP和AspectJ的关系 3. Spring Boot AOP4. 扩展4.1 AspectJ织入方式详解 参考 Java常用的AO…...

220V转12V芯片-交流45v-265v输入,固定12v输出峰值电流600MA

标题&#xff1a;220V转12V芯片&#xff0c;实现宽电压输入和固定12V输出 摘要&#xff1a;本文介绍了一款具备宽电压输入范围&#xff08;45V-265V&#xff09;和固定12V输出的220V转12V芯片。该芯片内置了650V高压MOS管&#xff0c;并通过CS电阻调节输出电流&#xff0c;最大…...

TOGAF架构开发方法—初步阶段

本章描述了满足新企业体系结构业务指令所需的准备和启动活动,包括组织特定体系结构框架的定义和原则的定义。 一、目标 初步阶段的目标是: 确定组织所需的体系结构功能: 审查进行企业架构的组织背景确定受体系结构功能影响的企业组织的元素并确定其范围确定与架构功能相交的…...

软件定制APP开发步骤分析|小程序

软件定制APP开发步骤分析|小程序 软件定制开发步骤&#xff1a; 1.需求分析&#xff1a; 这是软件定制开发的第一步&#xff0c;也是最关键的一步。在这个阶段&#xff0c;软件开发团队需要与客户进行沟通&#xff0c;了解客户的具体需求和期望。通过讨论和交流&#xff0c;确…...

postman接口传参案例

目录 案例1&#xff1a; 接口A 接口B 案例2&#xff1a; //断言 案例1&#xff1a; 接口A 根据返回值需要从返回值中提取userid值&#xff0c;在Tests标签栏下编写脚本 //获取返回的响应值&#xff0c;并转化为json格式 var jsonData pm.response.json(); // 获取返回…...

【2023华为杯A题】WLAN网络信道接入机制建模(代码、思路.....)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

CFCA企业版通配符SSL证书

CFCA是中国CFCA企业版通配符SSL证书金融认证中心的缩写&#xff0c;即China Financial Certification Authority。它是一家经过中国人民银行和国家信息安全机构批准成立的国家级权威安全认证机构&#xff0c;也是国际CA浏览器联盟组织&#xff08;CA/Browser Forum&#xff09;…...

基于ASCON的AEAD

1. 引言 前序博客&#xff1a; ASCON&#xff1a;以“慢而稳”赢得NIST轻量级加密算法标准密码学中的AEAD(authenticated encryption with associated data) 对称密钥加密过去数年来已发生改变&#xff0c;具体为&#xff1a; 当今主要使用stream ciphers&#xff0c;因其比…...

汇编宏伪指令介绍

1、汇编宏伪指令介绍 .macro macname macargs .endm&#xff08;1&#xff09;“.macro"和”.endm"表示宏定义的开始和结束&#xff1b; &#xff08;2&#xff09; “.macro"后面接着宏定义的名字&#xff0c;然后是参数&#xff0c;参数后面的宏定义的实现…...

优化系统报错提示信息,提高人机交互(一)

1、常规报错及处理 package com.example.demo.controller;import com.example.demo.service.IDemoService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.w…...

FPGA纯verilog实现8路视频拼接显示,提供工程源码和技术支持

目录 1、前言版本更新说明免责声明 2、我已有的FPGA视频拼接叠加融合方案3、设计思路框架视频源选择OV5640摄像头配置及采集静态彩条视频拼接算法图像缓存视频输出 4、vivado工程详解5、工程移植说明vivado版本不一致处理FPGA型号不一致处理其他注意事项 6、上板调试验证并演示…...

spring boot项目一次性能测试的总结

满足标准&#xff1a;并发大于等于100 &#xff0c;平均响应时间小于等于3秒 项目在压测过程中并发数只有50&#xff0c;在并发数100的情况下有很多请求链接是失败的 我们该如何入手去处理这些问题并提高并发数呢&#xff1f; 1、首先从压测结果入手&#xff0c;对不满足标准…...

10分钟设置免费海外远程桌面

前言 本教程将向您介绍如何使用 Amazon Lightsail 服务的免费套餐轻松搭建属于您的远程桌面。依托于 Amazon 全球可用区&#xff0c;您可以在世界各地搭建符合您配置需求的远程桌面。 本教程需要先拥有亚马逊云科技海外账户。现在注册亚马逊云科技账户可以享受12个月免费套餐…...

基于复旦微的FMQL45T900全国产化ARM核心模块(100%国产化)

TES745D是一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板。该核心板将复旦微的FMQL45T900&#xff08;与XILINX的XC7Z045-2FFG900I兼容&#xff09;的最小系统集成在了一个87*117mm的核心板上&#xff0c;可以作为一个核心模块&#xff0c;进行功能性扩展&#xff0c;能…...

2023.9.11 关于传输层协议 UDP和TCP 详解

目录 UDP协议 TCP协议 TCP十大核心机制 确认应答 超时重传 连接管理&#xff08;三次握手 四次挥手&#xff09; 滑动窗口 流量控制 拥塞控制 延时应答 捎带应答 面向字节流 粘包问题 TCP 中的异常处理 经典面试题 对比 TCP 和 UDP 如何使用 UDP 实现可靠传…...

thinkphp8路由

thinkphp8已出来有好一段时间了。这些天闲来无事&#xff0c;研究了下tp8的路由。默认情况下&#xff0c;tp8的路由是在route\app.php的文件里。但在实际工作中&#xff0c;我们并不会这样子去写路由。因为这样不好管理。更多的&#xff0c;是通过应用级别去管理路由。假如项目…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...