Sharding-JDBC分库分表之SpringBoot分片策略

Sharding-JDBC系列

1、Sharding-JDBC分库分表的基本使用

2、Sharding-JDBC分库分表之SpringBoot分片策略

前言

前一篇以一个示例分享了Sharding-JDBC的基本使用。在进行分库分表时,可以设置分库分表的分片策略,在示例中,使用的是最简单的inline分片策略。本篇详细的给大家分享一下Sharding-JDBC的分片策略。

核心概念

在开始讲解分片策略之前,先熟悉几个核心概念。

2.1 逻辑表

水平拆分表后,每个小的表的结构都是一样的,这些相同结构的小表可以使用一个逻辑表来表示,是SQL中表的逻辑标识。

如订单表通过主键按照一定规则(如模5)分为tb_order_1到tb_order_5,它们可以使用同一个逻辑表tb_order来标识。

2.2 真实表

在水平拆分的数据库中真实存在的物理表。

如上面的订单表示例,tb_order1到tb_order_5表为真实表。

2.3 分片键

用于将数据库(表)拆分(水平、垂直)的字段即为分片键。

如上面的订单表示例,订单主键为分片键。

如果没有分片键,所有的数据操作将执行全路由,性能较差。除了对单分片字段的支持,Apache ShardingSphere 也支持根据多个字段进行分片。

2.4 分片算法

用于将数据分片的算法,支持 =>=<=><BETWEENIN 进行分片。Sharding-JDBC不断完善实现自动分片算法,在最新的5.5.0中,提供了基于取模、基于哈希取模、基于分片边界、基于分片容量、基于可变时间的分片算法。开发者也可以通过实现基础的分片算法接口,自定义分片算法。

2.5 分片策略

分片策略由分片键和分片算法组成。分片键是从表格的字段中定义,分片算法是相对独立,可自定义的。不同的分片算法,对应了不同的分片策略。

在Sharding-JDBC中,分片策略分为四类,分别为行表达式分片策略、标准分片策略、复合分片策略、Hint分片策略。不同的分片算法构成了不同的分片策略,但所有的算法都归类到上面的四种类型中,只是具体的实现不同。

准备工作

以下以订单为例,分享一下四类分片策略的使用。先创建表tb_order_1、tb_order_2、tb_order_0_0、tb_order_0_1、tb_order_1_0、tb_order_1_1六张表。

行表达式分片策略

行表达式分片策略(InlineShardingStrategy),无需自定义分片算法,框架已默认实现,适用于做简单的分片算法,是四类分片策略中最简单的。

使用时,在配置中使用Groovy表达式,提供对SQL语句中分片键的=和IN的分片操作支持,仅支持单分片键。

4.1 Groovy表达式概述

行表达式的使用非常直观,只需要在配置中使用 ${ expression } 或 $->{ expression } 标识行表达式即可。目前支持数据节点和分片算法这两个部分的配置。行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。

如:${begin..end} 表示范围区间、${[unit1, unit2, unit_x]} 表示枚举值。

${['tb_order', 'tb_order_goods']}_${1..2},最终解析为:tb_order_1、tb_order_2、tb_order_goods_1、tb_order_goods_2

行表达式中如果出现连续多个 ${ expression } 或 $->{ expression } 表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合。

4.2 示例

行表达式分片策略使用时非常简洁,分片配置如下:

spring:shardingsphere:datasource:names: order1,order2sharding:tables:tb_order: #逻辑表database-strategy: #分库策略inline:  # 行表达式分片策略sharding-column: member_idalgorithm-expression: order$->{member_id % 2 + 1} #以member_id模2 + 1,如member_id为3,则存放在order2数据库中actual-data-nodes: order$->{1..2}.tb_order_$->{1..2}table-strategy: #分表策略inline:  # 行表达式分片策略sharding-column: order_idalgorithm-expression: tb_order_$->{order_id % 2 + 1}

1)分库策略

spring.shardingsphere.sharding.tables.tb_order.database-strategy.inline

2)分表策略

spring.shardingsphere.sharding.tables.tb_order.table-strategy.inline

3)其他配置

sharding-column分片键,表中的字段

algorithm-expression:算法表达式,Groovy表达式。tb_order_$->{order_id % 2 + 1},表示以order_id模2后加1为分片算法。如order_id为2,则操作tb_order_1的表

详细的示例见:

Sharding-JDBC分库分表的基本使用-CSDN博客

注:行表达式分片策略仅支持SQL中分片键包含 =、IN 的分片处理,对于 > 、< 等的SQL语句,系统会报错。

标准分片策略

标准分片策略(StandardShardingStrategy),用于处理使用单一键作为分片键的 =、IN、BETWEEN AND、>、<、>=、<= 进行分片的场景。

标准分片策略提供了PreciseShardingAlgorithm(精准分片)和 RangeShardingAlgorithm(范围分片)两种分片算法接口。

使用时,精准分片算法是必现实现的算法,用于处理SQL中分片键含=、IN 的分片处理。范围分片算法用于处理SQL中分片键含 >、<、>=、<= 、BETWEEN AND的分片处理,是非必选的。

注:如果没有实现范围分片算,而SQL中使用了BETWEEN AND的分片处理,那么系统会报错。

说明:在最新的5.5.0的版本,标准分片策略整合了精准分片和范围分片,对应的算法接口为StandardShardingAlgorithm。

5.1 精准分片算法

通过实现PreciseShardingAlgorithm接口实现精准分片算法,该接口只有一个方法,源码如下:

public interface PreciseShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {/*** @param availableTargetNames 可用的datasource或table的名称集合* @param shardingValue sql中,传入的分片键的值* @return*/String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<T> shardingValue);
}

对于数据库分片,第一个参数为配置的可用的数据库的名称集合;对于表分片,第一个参数为配置的可用的表的名称集合。所以对于数据库分片和表分片,实现逻辑一样,此处以表分片为例。

5.1.1 自定义表分片算法

package com.jingai.sharing.jdbc.algorithm;public class StandardShardingAlgorithm implements PreciseShardingAlgorithm<Long> {@Overridepublic String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> preciseShardingValue) {for (String tableName : tableNames) {String mod = preciseShardingValue.getValue() % tableNames.size() + 1 + Strings.EMPTY;if(tableName.endsWith(mod)) {return tableName;}}throw new IllegalArgumentException("找不到匹配的表分片");}
}

以上通过分片键对真实表个数取模加1作为分片的算法。

如:有两个表tb_order_1和tb_order_2,传入的分片键的值为3,则返回tb_order_2的表名字符串

5.1.2 分片配置

spring:shardingsphere:sharding:tables:tb_order: #逻辑表table-strategy:standard:   sharding-column: order_id   #分片键。对id进行分表precise-algorithm-class-name: com.jingai.sharing.jdbc.algorithm.StandardShardingAlgorithm  #精准分片算法

配置方式是在对应的datasource-strategy或table-strategy后面用standard标识标准分片策略。

standard:标识标准分片策略

precise-algorithm-class-name:指定精准分片算法的全路径类名

5.1.3 结果小结

1)精准分片算法根据每个分片键的值,返回分片键所在的表。只处理SQL中分片键含=、IN 的分片处理;

1.1)如果是=的分片,执行一次精准分片算法;

1.2)如果是IN的分片,IN中有几个值,执行几次精准分片算法;

根据返回的最终真实表的个数,分表执行对应SQL操作。同一个真实表的多次操作会进行合并处理,如:IN中传入1、2、3三个数,执行3次的精准分片算法,分别返回tb_order_2、tb_order_1、tb_order_2,则最终执行两条查询。

2)对于非=、IN的分片处理,系统报错;

5.2 范围分片算法

通过实现RangeShardingAlgorithm接口实现范围分片算法,该接口只有一个方法,源码如下:

public interface RangeShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {/*** @param availableTargetNames 可用的datasource或table的名称集合* @param shardingValue sql中,传入的分片键的值区间* @return*/Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<T> shardingValue);
}

通精准分片算法一样,数据库分片和表分片用的同一个接口。此处以表分片为例。

5.2.1 自定义表分片算法

package com.jingai.sharing.jdbc.algorithm;import com.google.common.collect.Range;
import org.apache.logging.log4j.util.Strings;
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.util.Collection;
import java.util.HashSet;
import java.util.Set;public class StandardShardingAlgorithm implements PreciseShardingAlgorithm<Long>, RangeShardingAlgorithm<Long> {@Overridepublic String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> preciseShardingValue) {for (String tableName : tableNames) {String mod = preciseShardingValue.getValue() % tableNames.size() + 1 + Strings.EMPTY;if(tableName.endsWith(mod)) {return tableName;}}throw new IllegalArgumentException("找不到匹配的表分片");}@Overridepublic Collection<String> doSharding(Collection<String> tableNames, RangeShardingValue<Long> rangeShardingValue) {Range<Long> valueRange = rangeShardingValue.getValueRange();Long lower = valueRange.hasLowerBound() ? valueRange.lowerEndpoint() : null;Long upper = valueRange.hasUpperBound() ? valueRange.upperEndpoint() : null;// 如果区间不确定,则需要全表操作if(lower == null || upper == null) {return tableNames;}Set<String> rs = new HashSet<>();// 循环计算需要用到的表for (long i = lower; i < upper ; i ++) {for(String name : tableNames) {String mod = i % tableNames.size() + 1 + Strings.EMPTY;if(name.endsWith(mod)) {rs.add(name);}}}return rs;}
}

以上代码为完整的标准分片策略算法,同时实现了精准分片算法和范围分片算法。算法的逻辑都是按照分片键取模加1。

5.2.2 分片配置

spring:shardingsphere:datasource:names: order1 #数据源名称,有几个数据源就写几个名字,和url中的数据库名字保持一致order1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shardingjdbctest?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: 123456#分表策略#按照id分表,id使用雪花算保证全局唯一,具体算法:tb_order是表前缀,拼接上:$->{id % 2}  的值sharding:tables:tb_order: #逻辑表actual-data-nodes: order1.tb_order_$->{1..2}  #order1:数据源名称;两个tb_order表,分别为tb_order_1和tb_order_2key-generator: # 指定主键生成策略column: order_idtype: SNOWFLAKEtable-strategy:standard:   # 标准分片策略sharding-column: order_id   #分片键。对id进行分表precise-algorithm-class-name: com.jingai.sharing.jdbc.algorithm.StandardShardingAlgorithm  #精准分片算法range-algorithm-class-name: com.jingai.sharing.jdbc.algorithm.StandardShardingAlgorithm  #范围分片算法

range-algorithm-class-name:指定范围分片算法的全路径类名

5.2.3 结果小结

对于分片键含 >、<、>=、<= 的分片,在范围分片算法中的ValueRange中,lower和upper只有其中一个有值;

复合分片策略

复合分片策略(ComplexShardingStrategy),用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。处理分片键中含有 =、IN、BETWEEN AND、>、<、>=、<= 等操作符进行分片的场景。

复合分片策略提供了ComplexKeysShardingAlgorithm接口,通过重写doSharding()方法实现复合分片算法。源码如下:

public interface ComplexKeysShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {/*** @param availableTargetNames 可用的datasource或table的名称集合* @param shardingValue 存放分片键及对应的值集合或值区间* @return*/Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<T> shardingValue);
}

数据库分片和表分片都是实现同一个接口,此处以表按member_id和order_id分片为例。

6.1 自定义表分片算法

package com.jingai.sharing.jdbc.algorithm;import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;import java.util.Collection;
import java.util.HashSet;
import java.util.Map;public class OrderComplexShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {@Overridepublic Collection<String> doSharding(Collection<String> tableNames, ComplexKeysShardingValue<Long> complexKeysShardingValue) {// IN、= 的处理Map<String, Collection<Long>> valuesMap = complexKeysShardingValue.getColumnNameAndShardingValuesMap();Collection<Long> memberIds = valuesMap.containsKey("member_id") ? valuesMap.get("member_id") : new HashSet<>();Collection<Long> orderIds = valuesMap.containsKey("order_id") ? valuesMap.get("order_id") : new HashSet<>();// 区间的处理Map<String, Range<Long>> rangeMap = complexKeysShardingValue.getColumnNameAndRangeValuesMap();if(rangeMap.containsKey("member_id")) {memberIds.addAll(getRangValue(rangeMap.get("member_id"), tableNames.size()));}if(rangeMap.containsKey("order_id")) {orderIds.addAll(getRangValue(rangeMap.get("order_id"), tableNames.size()));}return getTableNames(memberIds, orderIds, tableNames);}private Collection<Long> getRangValue(Range<Long> range, int tableNameSize) {Long lower = range.hasLowerBound() ? range.lowerEndpoint() : null;Long upper = range.hasUpperBound() ? range.upperEndpoint() : null;Collection<Long> rs = new HashSet<>(tableNameSize);if(lower == null || upper == null) {lower = 1l;upper = (long)tableNameSize;} else {upper = upper > (lower + tableNameSize) ? (lower + tableNameSize) : upper;}for (long i = lower ; i <= upper ; i ++) {rs.add(i);}return rs;}private Collection<String> getTableNames(Collection<Long> memberIds, Collection<Long> orderIds, Collection<String> tableNames) {int size = tableNames.size();Collection<String> rs = new HashSet<>(size < 16 ? size : 16);// 通过对memberId和orderId分别取模进行分库size = size / 2; // 两个分片键String underline = "_";// 如果没有memberId值,则根据orderId扫描,不处理系统会报错if(memberIds.isEmpty()) {for(long orderId : orderIds) {String suffix = underline + orderId % size;for(String tableName : tableNames) {if(tableName.endsWith(suffix)) {rs.add(tableName);break;}}}} else if(orderIds.isEmpty()) {for(long memberId : memberIds) {String middle = underline + memberId % size + underline;for(String tableName : tableNames) {if(tableName.contains(middle)) {rs.add(tableName);break;}}}} else {for (long memberId : memberIds) {for(long orderId : orderIds) {String suffix = memberId % size + "_" + orderId % size;for(String tableName : tableNames) {if(tableName.endsWith(suffix)) {rs.add(tableName);break;}}}}}return rs;}
}

在ComplexKeysShardingAlgorithm接口中,包含了精准和范围分片的算法。算法为先按member_id取模,然后再按order_id取模。如果只有member_id,没有order_id,则对member_id下的所有表操作;如果只有order_id没有member_id,则对order_id下的所有member的表操作。

注:在自定义分片算法时,对于存在分片键的操作(即进入了自定义分片算法),都需要有返回值,否则系统会报找不到路由信息的异常错误。

6.2 分片配置

# 单数据库,inline分片策略测试
server:port: 8080#sharding-jdbc分片规则配置
spring:shardingsphere:datasource:names: order1 #数据源名称,有几个数据源就写几个名字,和url中的数据库名字保持一致order1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shardingjdbctest?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: 123456#分表策略#按照id分表,id使用雪花算保证全局唯一sharding:tables:tb_order: #逻辑表actual-data-nodes: order1.tb_order_$->{0..1}_$->{0..1}  #order1:数据源名称;四个tb_order表,分别为tb_order_0_0到tb_order_1_1key-generator: # 指定主键生成策略column: order_idtype: SNOWFLAKEtable-strategy:complex:   # 复合分片策略sharding-columns: member_id, order_id   #分片键algorithm-class-name: com.jingai.sharing.jdbc.algorithm.OrderComplexShardingAlgorithm  #分片算法props:sql:show: true  # 是否打印sql

配置方式是在对应的datasource-strategy或table-strategy后面用complex标识复合分片策略。

complex:表示复合分片策略

sharding-columns指定复合分片算法的分片键,多个中间用","隔开

algorithm-class-name指定复合分片算法的全路径类名

Hint分片策略

Hint分片策略(HintShardingStrategy),用于处理使用 Hint 行分片的场景。相比另外三种策略,该分片策略无需配置分片键,而是在执行数据库操作之前,进行分片信息的设定,使得数据库操作指定的分库、分表中执行。

Hint分片策略通过Hint API实现指定操作,使得分片规则变成个性化配置。

Hint分片策略提供了HintShardingAlgorithm接口,实现自定义Hint分片算法。源码如下:

public interface HintShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {/*** @param availableTargetNames 可用的datasource或table的名称集合* @param shardingValue 分片键及设置的分片键的值* @return*/Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<T> shardingValue);
}

数据库分片和表分片都是实现同一个接口,此处以表按member_id和order_id分片为例。

7.1 自定义表分片算法

public class OrderHintShardingAlgorithm implements HintShardingAlgorithm<Integer> {@Overridepublic Collection<String> doSharding(Collection<String> tableNames, HintShardingValue<Integer> hintShardingValue) {Collection<String> rs = new HashSet<>();for(Integer val : hintShardingValue.getValues()) {String suffix = "_" + (val % tableNames.size() + 1);for(String tableName : tableNames) {if(tableName.endsWith(suffix)) {rs.add(tableName);break;}}}return rs.isEmpty() ? tableNames : rs;}
}

算法比较简单,以设置的分片键的值取模。

7.2 分片配置

# 单数据库,inline分片策略测试
server:port: 8080#sharding-jdbc分片规则配置
spring:shardingsphere:datasource:names: order1 #数据源名称,有几个数据源就写几个名字,和url中的数据库名字保持一致order1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shardingjdbctest?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: 123456#分表策略#按照id分表,id使用雪花算保证全局唯一,具体算法:tb_order是表前缀,拼接上:$->{id % 2}  的值sharding:tables:tb_order: #逻辑表actual-data-nodes: order1.tb_order_$->{1..2}  #order1:数据源名称;两个tb_order表,分别为tb_order_1和tb_order_2key-generator: # 指定主键生成策略column: order_idtype: SNOWFLAKEtable-strategy:hint:  # hint分片策略algorithm-class-name: com.jingai.sharing.jdbc.algorithm.OrderHintShardingAlgorithm  #分片算法props:sql:show: true  # 是否打印sql

7.3 方法

@RestController
public class OrderController {@Resourceprivate OrderService orderService;@RequestMapping("order")public String order(OrderEntity order) {// 清除上一次的规则HintManager.clear();// 指定插入到1的表HintManager hintManager = HintManager.getInstance();hintManager.addTableShardingValue("tb_order", 1);order.setOrderTime(new Date());long insert = orderService.insert2(order);return insert > 0 ? "success" : "fail";}
}

在执行插入之前,通过HintManager的addTableShardingValue()指定如果是逻辑表为tb_order,则存放在分片键值为1的小表中,结合上面的算法,存放在tb_order_2表中。无论执行多少次这个方法,数据都是存放在tb_order_2这个表。可以执行多次addTableShardingValue()方法,添加多个分片键值。

HintManager在使用之前都需要先执行HintManager.clear(),因为设置的信息是保存在ThreadLocal,可能会冲突。

addDatabaseShardingValue():添加数据库分片键值;

addTableShardingValue():添加表分片键值;

setMasterRouteOnly():在读写分离的数据库中,强制从主库中读取。在最新的5.5.0版本,该方法被setWriteRouteOnly()取代;

小结

以上为本篇分享的全部内容。以下做个小结:

1)行表达式分片策略只适合分片键中包含=、IN的分片处理,无需自定义分片算法,只支持单分片键;

2)标准分片策略适合分片键中包含 =、IN、BETWEEN AND、>、<、>=、<=的分片处理,需自定义分片算法,只支持单分片键;

3)复合分片策略适合分片键中包含 =、IN、BETWEEN AND、>、<、>=、<=的分片处理,需自定义分片算法,支持多个分片键;

4)Hint分片策略适合所有操作的分片处理,需自定义分片算法,可在每次执行前通过HintManager个性化设置分片键值;

5)对于存在分片键的数据库操作,如果没有返回对应的分片库或分片表,则系统会提示找不到路由信息的异常;

以上的示例的完整代码可以结合

Sharding-JDBC分库分表的基本使用-CSDN博客

博文中的示例,是在此基础上修改了配置文件。

说明:以上分片策略算法只是为了演示功能,实际项目的分片需要根据业务需要进行设计。特别是复合分片策略的算法,在实际项目中,应该没人会如此设计。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

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

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

相关文章

面对数据不一致性的解决方案:

polarDB是读写分离和计算存储分离的分布式数据库&#xff0c;并且副本的log replicate是基于Parallel-Raft协议来实现的。所以在瞬时进行写和读的操作时&#xff0c;是不可避免会存在数据一致性问题&#xff0c;导致这个数据一致性问题的原因不是事务&#xff0c;而是多副本日志…

springboot篮球馆管理系统-计算机毕业设计源码21945

目 录 摘要 1 绪论 1.1选题背景 1.2研究意义 1.3论文结构与章节安排 2 篮球馆管理系统系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2.4 …

数据结构--二叉树收尾

1.二叉树销毁 运用递归方法 分类&#xff1a; 根节点左子树右子树&#xff08;一般都是这个思路&#xff0c;不断进行递归即可&#xff09; 选择方法&#xff08;分析)&#xff1a; 前序&#xff1a;如果直接销毁根就无法找到左子树右子树 中序&#xff1a;也会导致丢失其…

【算法】(C语言):快速排序(递归)、归并排序(递归)、希尔排序

快速排序&#xff08;递归&#xff09; 左指针指向第一个数据&#xff0c;右指针指向最后一个数据。取第一个数据作为中间值。右指针指向的数据 循环与中间值比对&#xff0c;若大于中间值&#xff0c;右指针往左移动一位&#xff0c;若小于中间值&#xff0c;右指针停住。右…

红酒的奇幻之旅:从葡萄园到酒杯的魔法

在世界的某个角落&#xff0c;隐藏着一场关于红酒的奇幻之旅。这是一场从葡萄园到酒杯的魔法变幻&#xff0c;将大自然的馈赠与人类的智慧很好结合&#xff0c;最终呈现在我们眼前的&#xff0c;是一杯散发着迷人香气的雷盛红酒。 一、葡萄园的魔法启幕 当清晨的第一缕阳光洒落…

windows server 2019 更新补丁

1 点击 搜索按键--windows 更新设置 2 点击 安装补丁 3 安装完成&#xff0c;重新启动服务器

四、Python日志系统之日志文件的备份和删除

import os import datetime import logging from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer """实现代码中处理日志文件的备份和删除""" class UserLog:def __init__(self):self.logger logging…

简述 Kamailio 的多租户

如题&#xff0c;大家猜下我会怎么写 过几天公布答案 首先&#xff0c;是认证表 如果单租户, insert into subscriber(username, password) values (1000, 1234)&#xff0c;这样就行 多租户则不然, insert into subscriber(username, domain, password) values (1000, abc.…

WebGIS面试题

文章目录 1. 前端1.1. 选择器的优先级1.2. CSS 中它的布局有哪些&#xff1f;1.3. CSS3 的新特性1.4. CSS 的两种盒子模型1.5. CSS 的伪元素选择器和伪类选择器有哪些&#xff1f;1.6. ES6 的新特性1.7. 谈谈你对 promise 的理解1.8. 简单说一下原型链1.9. 简单说一下深浅拷贝1…

CPLD编程注意事项

1、CPLD体积小&#xff0c;如果仅仅是完成简单的触发等时序&#xff0c;完全可以采用CPLD这类器件。 2、CPLD资源相当少&#xff0c;一般逻辑资源如上图&#xff0c;才160&#xff0c;稍微不注意&#xff0c;就会超标&#xff0c;所以&#xff0c;寄存器输入一定要尽量减少&…

算法小练之 位运算基础

前言 今天正式走入&#xff0c;位运算这个章节&#xff0c;关于这一部分我会先介绍几个重要的知识点&#xff0c;然后再根据几个力扣上的题来讲解。 了解6种位操作 总所周知&#xff0c;变量在计算机中都是二进制存储的&#xff0c;比如一个变量int a 1&#xff1b; 它的存…

nvidia driver和cuda版本较低,ubuntu系统更新nvidia驱动的方法(对于小白最快最最保险的方法)

问题描述&#xff1a; 系统&#xff1a;ubuntu22.04LTS 这两天安装另一个低版本的pytorch环境&#xff0c;提示我的cuda版本很旧&#xff0c;然后运行程序时候甚至直接报错&#xff0c;如下所示&#xff1a; .local/lib/python3.10/site-packages/torch/cuda/__init__.py&quo…

高通开发系列 - 使用QFIL工具单刷某个镜像文件

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 返回:专栏总目录 目录 背景过程记录背景 有时候设备中刷的是user版本,无法使用fastboot刷单个镜像,这个时候该怎么办呢? 要解决在user…

Linux 一键部署Mysql 8.4.1 LTS

mysql 前言 MySQL 是一个基于 SQL(Structured Query Language)的数据库系统,SQL 是一种用于访问和管理数据库的标准语言。MySQL 以其高性能、稳定性和易用性而闻名,它被广泛应用于各种场景,包括: Web 应用程序:许多动态网站和内容管理系统(如 WordPress)使用 MySQL 存…

Python从0到100(三十五):beautifulsoup的学习

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

【网络安全科普】网络安全指南请查收

随着社会信息化深入发展&#xff0c;互联网对人类文明进步奖发挥更大的促进作用。但与此同时&#xff0c;互联网领域的问题也日益凸显。网络犯罪、网络监听、网络攻击等是又发生&#xff0c;网络安全与每个人都息息相关&#xff0c;下面&#xff0c;一起来了解网络安全知识吧。…

上海市计算机学会竞赛平台2023年1月月赛丙组新年灯会

题目描述 新春佳节之际&#xff0c;路上挂起了一排喜气洋洋的大红灯笼&#xff0c;从左至右编号分别为1,2,...,&#x1d45b;1,2,...,n。但小爱发现&#xff0c;目前有&#x1d45d;p个灯笼不亮了&#xff0c;很是影响美观。 请你帮助小爱计算&#xff0c;最少修复多少个灯笼…

锐捷统一上网行为管理与审计系统static_convert接口远程命令执行漏洞复现 [附POC]

文章目录 锐捷统一上网行为管理与审计系统static_convert接口远程命令执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 锐捷统一上网行为管理与审计系统static_convert接口远程命令执行漏洞复现 [附POC] 0x…

如何快速将Excel定义的表结构转换为MySQL的建表语句

目录 引言 方法一&#xff1a;使用Python编程 步骤一&#xff1a;安装必要的库 步骤二&#xff1a;读取Excel文件 步骤三&#xff1a;编写函数生成建表语句 注意事项 方法二&#xff1a;使用Excel VBA 步骤一&#xff1a;启用VBA编辑器 步骤二&#xff1a;编写VBA代码…

共筑智能未来 | 思腾合力闪耀2024世界人工智能大会(WAIC 2024)

在刚刚结束的2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;上&#xff0c;思腾合力作为行业领先的人工智能基础架构解决方案提供商&#xff0c;凭借卓越的产品和解决方案&#xff0c;成为展会上的亮点之一。此次盛会不仅展示了全球人工智…