spring-boot 2.7.18整合sharding-jdbc-spring-boot-starter 4.1.1

sharding-jdbc

基本概念

逻辑表

水平拆分的数据表的总称。例:订单数据表根据主键尾数拆分为10张表,分别是 t_order_0 、 t_order_1 到 t_order_9 ,他们的逻辑表名为 t_order 。

真实表

在分片的数据库中真实存在的物理表。即上个示例中的 t_order_0 到 t_order_9 。

数据节点

数据分片的最小物理单元。由数据源名称和数据表组成,例:ds_0.t_order_0 。

分片键

用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。

分片算法

通过分片算法将数据分片,支持通过=>=<=><BETWEENIN分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高。

目前提供4种分片算法。由于分片算法和业务实现紧密相关,因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。

  • 精确分片算法

对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。

  • 范围分片算法

对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用。

  • 复合分片算法

对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。

  • Hint分片算法

对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。

分片策略

包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供5种分片策略。

具体算法实现,需要在配置中指定实现类,他会根据你的配置找到对应算法

  • 标准分片策略

对应StandardShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。

StandardShardingStrategy 是一个配置工具,用于帮助你指定分片键和分片算法。你无需继承它,而是通过配置来指定具体的分片算法(如 PreciseShardingAlgorithmRangeShardingAlgorithm)的实现。这两个算法类需要你自行实现,以处理具体的分片逻辑。

  • 复合分片策略

对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。

  • 行表达式分片策略

对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0t_user_7

  • Hint分片策略

对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。

  • 不分片策略

对应NoneShardingStrategy。不分片的策略。

分片策略是一个更高层次的概念,它定义了如何应用分片算法以及如何处理不同类型的分片需求。分片策略的主要任务是管理和协调分片算法的使用,以应对不同的查询模式和业务需求。它通常包含以下几个方面:

  1. 分片键的选择
    • 确定用于分片的列,比如 order_idorder_date
    • 分片键决定了分片算法如何执行。
  2. 分片算法的选择和配置
    • 根据查询类型配置合适的分片算法,比如精确分片算法或范围分片算法。

spring-boot 2.7.18整合sharding-jdbc-spring-boot-starter 4.1.1

5的整合不了暂时有问题

需求

需求一:根据创建时间的年月分表

需求二:根据 省份和创建时间的年月 分表

还需要自动创建表

代码

https://github.com/Aerozb/learn-project/tree/main/sharding/version4

创建表

CREATE TABLE `sharding_user` (`id` bigint NOT NULL COMMENT '主键',`username` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户名',`province_abbreviation` varchar(8) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '省份拼音缩写',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户表';

依赖

使用druid-spring-boot-starter 会报错Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

所以直接用druid

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><!--        使用druid-spring-boot-starter 会报错Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.23</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.6</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.4.0</version></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>2.1.0</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.18</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

配置

单片和多片分键都有写,用哪个启用那个,只能启用一个分片策略

spring:shardingsphere:datasource:names: learn # 数据源名称,多数据源以逗号分隔learn:type: com.alibaba.druid.pool.DruidDataSource # 数据库连接池类名称driver-class-name: com.mysql.cj.jdbc.Driver # 数据库驱动类名url: jdbc:mysql://47.116.44.79:3306/learn?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # 数据库url连接username: root # 数据库用户名password: 123456 # 数据库密码sharding:default-data-source-name: learntables:sharding_user:# 会根据这里的表达式生成分表名,传入到各个分片算法的doSharding方法的Collection<String> availableTargetNamesactual-data-nodes: learn.sharding_user# 分表策略table-strategy:# 用于单分片键的标准分片场景
#            standard:
#              sharding-column: create_time # 分片列名称
#              precise-algorithm-class-name: com.yhy.sharding.SinglColumnPreciseShardingAlgorithm # 精确分片算法类名称,用于=和IN。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
#              range-algorithm-class-name: com.yhy.sharding.SinglColumnPreciseShardingAlgorithm # 范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器# 用于多分片键的复合分片场景complex:sharding-columns:  province_abbreviation,create_time # 分片列名称,多个列以逗号分隔algorithm-class-name: com.yhy.sharding.MultiColumnComplexKeysShardingAlgorithm # 复合分片算法类名称。该类需实现ComplexKeysShardingAlgorithm接口并提供无参数的构造器props:sql.show: true # 是否开启SQL显示,默认值: falsemybatis-plus:configuration:#开启驼峰命名自动映射map-underscore-to-camel-case: true#开启日志打印log-impl: org.apache.ibatis.logging.stdout.StdOutImpltype-aliases-package: com.yhy.entity#扫描mapper文件mapper-locations: classpath:mapper/*.xmlpagehelper:helperDialect: mysqlreasonable: truesupportMethodsArguments: trueparams: count=countSql

表操作mapper类

用来创建表和判断表是否存在

@Mapper
public interface TableMapper {void createTable(@Param("tableName") String tableName, @Param("templateTableName") String templateTableName);int existTable(@Param("tableSchema") String tableSchema, @Param("tableName") String tableName);}

表操作mapper.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.yhy.mapper.TableMapper"><select id="existTable" resultType="int">SELECT COUNT(*)FROM information_schema.tablesWHERE table_schema = #{tableSchema}AND table_name = #{tableName}</select><update id="createTable">CREATE TABLE ${tableName} like ${templateTableName}</update>
</mapper>

常量

public interface Constant {/*** 需要分片的库*/String SHARDING_DB_NAME = "learn";/*** 需要分片的表*/String SHARDING_TABLE_NAME = "sharding_user";
}

分片工具类

public class ShardingUtil {private static final Map<String, Integer> tableExistMap = new ConcurrentHashMap<>();private static TableMapper tableMapper;public static void setTableMapper(TableMapper tableMapper) {ShardingUtil.tableMapper = tableMapper;}public static void setTableExistMap(List<String> shardingTableNameList) {for (String shardingTableName : shardingTableNameList) {int shardingYearMonth = getShardingYearMonth(shardingTableName);tableExistMap.put(shardingTableName, shardingYearMonth);}}public static boolean isExistTableCache(String tableName) {return tableExistMap.containsKey(tableName);}/*** 不存在表,则创建* 日期大于上个月的,不创建** @param tableName         要创建的表名-分片后的表名* @param templateTableName 未分片的表*/public static void createTable(String tableName, String templateTableName) {if (isExistTableCache(tableName)) {return;}int shardingYearMonth = getShardingYearMonth(tableName);int nowYearMonth = Integer.parseInt(DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN));if (shardingYearMonth > nowYearMonth) {throw new RuntimeException("创建表失败超出当前年月:" + shardingYearMonth);}int row = tableMapper.existTable(Constant.SHARDING_DB_NAME, tableName);//表不存在则创建并塞入缓存if (row <= 0) {tableMapper.createTable(tableName, templateTableName);tableExistMap.put(tableName, shardingYearMonth);} else {tableExistMap.put(tableName, shardingYearMonth);}}/*** 获取日期最新的表** @param provinceAbbreviation 省份缩写* @return 最新日期的表对应的日期*/public static Date getExistLatestDate(String provinceAbbreviation) {return tableExistMap.entrySet().stream().filter(entry -> entry.getKey().contains(provinceAbbreviation)).map(Map.Entry::getValue).max(Integer::compareTo).map(latestYearMonth -> DateUtil.parse(String.valueOf(latestYearMonth), DatePattern.SIMPLE_MONTH_PATTERN)).orElseThrow(() -> new RuntimeException("不存在此省份分表:" + provinceAbbreviation));}private static int getShardingYearMonth(String tableName) {return Integer.parseInt(StrUtil.subSufByLength(tableName, DatePattern.SIMPLE_MONTH_PATTERN.length()));}
}

给工具类注入表操作mapper

/*** 项目启动后* 1.分表工具类注入属性* 2.把已有的真实表加载进缓存,否则项目重启缓存不见*/
@Slf4j
@Order(value = 1) // 数字越小 越先执行
@Component
public class ShardingTablesLoadRunner implements CommandLineRunner {@Resourceprivate TableMapper tableMapper;@Overridepublic void run(String... args) {// 给 分表工具类注入属性ShardingUtil.setTableMapper(tableMapper);//加载真实表缓存List<String> shardingTableNameList = tableMapper.getShardingTableName(Constant.SHARDING_DB_NAME, Constant.SHARDING_TABLE_NAME);ShardingUtil.setTableExistMap(shardingTableNameList);}
}

单个分片键策略-用于精确和范围查询(解决需求一)

/*** 单个分片键-根据年月分表*/
public class SingleColumnPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Date>, RangeShardingAlgorithm<Date> {/*** 这个方法用于处理精确分片,即处理单个分片键值的分片场景。例如,处理一个具体的订单 ID,决定它应该被路由到哪个数据源或表。** @param availableTargetNames 可用的目标数据源或表的集合* @param shardingValue        包含分片键值以及逻辑表名等信息的对象* @return 单张表*/@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {Date createTime = shardingValue.getValue();String shardingName = DateUtil.format(createTime, DatePattern.SIMPLE_MONTH_PATTERN);//要分片的表String logicTableName = shardingValue.getLogicTableName();//实际要查询的表名String tableName = logicTableName + "_" + shardingName;ShardingUtil.createTable(tableName, logicTableName);return tableName;}/*** 这个方法用于处理范围分片,即处理一段分片键值范围的分片场景。例如,处理一个范围查询(如查询某一段时间内的订单),决定这些记录应该被路由到哪些数据源或表。** @return 多张表*/@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> shardingValue) {Range<Date> range = shardingValue.getValueRange();String logicTableName = shardingValue.getLogicTableName();List<DateTime> dateRange = DateUtil.rangeToList(range.lowerEndpoint(), range.upperEndpoint(), DateField.MONTH);List<String> tableNameList = new ArrayList<>();//生成年月的分表名for (DateTime dateTime : dateRange) {String tableName = logicTableName + "_" + DateUtil.format(dateTime, DatePattern.SIMPLE_MONTH_PATTERN);//不存在此表,则不返回表名,否则查询时表不存在会报错if (ShardingUtil.isExistTableCache(tableName)) {tableNameList.add(tableName);}}return tableNameList;}}

自定义多片键(解决需求二)

/*** 多列复杂分片算法,根据省份缩写和年月分表*/
@Slf4j
public class MultiColumnComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {/*** 处理多列复杂分片** @param availableTargetNames 可用的目标表名集合* @param shardingValue        包含分片键值和逻辑表名等信息* @return 匹配的表名集合*/@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Comparable<?>> shardingValue) {String logicTableName = shardingValue.getLogicTableName();Map<String, Collection<Comparable<?>>> columnNameAndShardingValuesMap = shardingValue.getColumnNameAndShardingValuesMap();Map<String, Range<Comparable<?>>> columnNameAndRangeValuesMap = shardingValue.getColumnNameAndRangeValuesMap();//精确查询的省份Collection<Comparable<?>> provinceAbbreviationList = columnNameAndShardingValuesMap.get("province_abbreviation");//精确查询的创建时间Collection<Comparable<?>> createTimeList = columnNameAndShardingValuesMap.get("create_time");//范围查询的创建时间Range<Comparable<?>> createTimeRange = columnNameAndRangeValuesMap.get("create_time");//校验分片键validateInputs(provinceAbbreviationList, createTimeList, createTimeRange);//获取省份String provinceAbbreviation = getProvinceAbbreviation(provinceAbbreviationList);//精确查询if (CollUtil.isNotEmpty(createTimeList)) {return handlePreciseSharding(logicTableName, provinceAbbreviation, createTimeList);}//范围查询return handleRangeSharding(logicTableName, provinceAbbreviation, createTimeRange);}private void validateInputs(Collection<Comparable<?>> provinceAbbreviationList, Collection<Comparable<?>> createTimeList, Range<Comparable<?>> createTimeRange) {if (CollUtil.isEmpty(provinceAbbreviationList)) {throw new RuntimeException("路由表失败,province_abbreviation不能为空");}if (CollUtil.isEmpty(createTimeList) && createTimeRange == null) {throw new RuntimeException("路由表失败,create_time不能为空");}if (provinceAbbreviationList.size() > 1) {throw new RuntimeException("路由表失败,province_abbreviation精确查询只能查1个");}if (CollUtil.isNotEmpty(createTimeList) && createTimeList.size() > 1) {throw new RuntimeException("路由表失败,create_time精确查询只能查1个");}}private String getProvinceAbbreviation(Collection<Comparable<?>> valueList) {return valueList.stream().map(String::valueOf).findFirst().orElseThrow(() -> new RuntimeException("获取province_abbreviation异常"));}private Collection<String> handlePreciseSharding(String logicTableName, String provinceAbbreviation, Collection<Comparable<?>> createTimeList) {String tableName = logicTableName + "_" + provinceAbbreviation + "_" + createTimeList.stream().map(comparable -> DateUtil.format((Date) comparable, DatePattern.SIMPLE_MONTH_PATTERN)).findFirst().orElseThrow(() -> new RuntimeException("获取create_time异常"));ShardingUtil.createTable(tableName, logicTableName);return Collections.singleton(tableName);}private Collection<String> handleRangeSharding(String logicTableName, String provinceAbbreviation, Range<Comparable<?>> createTimeRange) {//必传Date startDate = getStartDate(createTimeRange);//不传或者大于上个月,就改为存在此省份表的最新日期Date endDate = getEndDate(createTimeRange, provinceAbbreviation);List<DateTime> dateRange = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);List<String> tableNameList = new ArrayList<>();//返回已存在表的表名for (DateTime dateTime : dateRange) {String tableName = logicTableName + "_" + provinceAbbreviation + "_" + DateUtil.format(dateTime, DatePattern.SIMPLE_MONTH_PATTERN);if (ShardingUtil.isExistTableCache(tableName)) {tableNameList.add(tableName);}}return tableNameList;}private Date getStartDate(Range<Comparable<?>> createTimeRange) {try {return (Date) createTimeRange.lowerEndpoint();} catch (IllegalStateException e) {throw new RuntimeException("请传入开始日期");}}private Date getEndDate(Range<Comparable<?>> createTimeRange, String provinceAbbreviation) {try {Date date = (Date) createTimeRange.upperEndpoint();String shardingYearMonth = DateUtil.format(date, DatePattern.SIMPLE_MONTH_PATTERN);String nowYearMonth = DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN);if (Integer.parseInt(shardingYearMonth) > Integer.parseInt(nowYearMonth)) {date = ShardingUtil.getExistLatestDate(provinceAbbreviation);}return date;} catch (IllegalStateException e) {return ShardingUtil.getExistLatestDate(provinceAbbreviation);}}
}

编写测试请求

先请求保存,在请求多片键multiColumnList

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/singleColumnList")public PageInfo<User> singleColumnList() {PageHelper.startPage(1, 10);LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();wrapper.ge(User::getCreateTime, DateUtil.parse("202302", DatePattern.SIMPLE_MONTH_PATTERN));wrapper.le(User::getCreateTime, new Date());List<User> list = userService.list(wrapper);return new PageInfo<>(list);}@GetMapping("/multiColumnList")public PageInfo<User> multiColumnList() {PageHelper.startPage(1, 10);LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();wrapper.eq(User::getProvinceAbbreviation, "wh");
//        wrapper.ge(User::getCreateTime,DateUtil.parse("202302", DatePattern.SIMPLE_MONTH_PATTERN));
//        wrapper.le(User::getCreateTime,new Date());wrapper.eq(User::getCreateTime, DateUtil.parse("202403", DatePattern.SIMPLE_MONTH_PATTERN));List<User> list = userService.list(wrapper);return new PageInfo<>(list);}@PostMapping("/save")public void save() {List<User> users = generateUsers(5);for (User user : users) {userService.save(user);}}public static List<User> generateUsers(int count) {List<User> users = new ArrayList<>();List<Date> dates = new ArrayList<>();List<String> provinceAbbreviation = new ArrayList<>();provinceAbbreviation.add("fz");provinceAbbreviation.add("bj");provinceAbbreviation.add("wh");provinceAbbreviation.add("hn");provinceAbbreviation.add("sh");dates.add(DateUtil.parse("202401", DatePattern.SIMPLE_MONTH_PATTERN));dates.add(DateUtil.parse("202402", DatePattern.SIMPLE_MONTH_PATTERN));dates.add(DateUtil.parse("202403", DatePattern.SIMPLE_MONTH_PATTERN));dates.add(DateUtil.parse("202404", DatePattern.SIMPLE_MONTH_PATTERN));dates.add(DateUtil.parse("202405", DatePattern.SIMPLE_MONTH_PATTERN));for (int i = 0; i < count; i++) {User user = new User();long snowflakeNextId = IdUtil.getSnowflakeNextId();user.setId(snowflakeNextId);user.setUsername("user" + snowflakeNextId);user.setProvinceAbbreviation(provinceAbbreviation.get(i));user.setCreateTime(dates.get(i));users.add(user);}return users;}}

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

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

相关文章

数据库开发-Mysql03

目录 1. 多表查询 1.1 概述 1.1.1 数据准备 1.1.2 介绍 1.1.3 分类 1.2 内连接 1.3 外连接 1.4 子查询 1.4.1 介绍 1.4.2 标量子查询 1.4.3 列子查询 1.4.4 行子查询 1.4.5 表子查询 1.5 案例 2. 事务 2.1 介绍 2.2 操作 2.3 四大特性 3. 索引 3.1 介绍 3…

Android基础-flutter

Flutter的功能和作用 一、引言 Flutter&#xff0c;作为Google开源的移动UI框架&#xff0c;自其诞生以来&#xff0c;便以其独特的魅力和强大的功能吸引了全球众多开发者的目光。Flutter不仅为开发者提供了构建高性能、高质量跨平台应用的能力&#xff0c;而且极大地简化了开…

实验室类管理平台LIMS系统的ui设计实例

实验室类管理平台LIMS系统的ui设计实例

leetcode64-Minimum Path Sum

题目 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 示例 1&#xff1a; 输入&#xff1a;grid [[1,3,1],[1,5,1],[4,2,1]] 输出&#xf…

项目管理工具的选择

1、为什么要用到项目管理工具 一个项目在启动后&#xff0c;需要做需求管理、计划排期&#xff0c;工作分解&#xff0c;开发、测试、验收&#xff0c;假设我们用excel来处理的话&#xff0c;会出现以下情况 &#xff08;1&#xff09;需求跟踪&#xff0c;如果用在线excel文…

第九十七节 Java面向对象设计 - Java Object.Finalize方法

Java面向对象设计 - Java Object.Finalize方法 Java提供了一种在对象即将被销毁时执行资源释放的方法。 在Java中&#xff0c;我们创建对象&#xff0c;但是我们不能销毁对象。 JVM运行一个称为垃圾收集器的低优先级特殊任务来销毁不再引用的所有对象。 垃圾回收器给我们一个…

weak的底层原理

weak 引用在 iOS 中通过维护一个全局的弱引用表来实现。当弱引用的对象被释放时&#xff0c;所有指向它的弱引用会被自动置为 nil&#xff0c;从而防止悬挂指针。 弱引用表&#xff08;Weak Table&#xff09;的键和值 理解弱引用表的键和值对于理解 weak 引用的底层机制非常重…

【加密与解密】【02】加密算法类型

加密算法类别 单向加密算法&#xff08;MD5&#xff0c;SHA&#xff0c;校验数据完整性&#xff09; 对称加密算法&#xff08;DES&#xff0c;数据存储加密&#xff09; 非对称加密算法&#xff08;RSA算法&#xff0c;数据传输加密&#xff09; 非对称加密和对称加密对比…

高通Android 12/13添加/移除不被清理后台应用

/*** 添加不被清理的后台应用** param packageName*/public void addBackgroundAliveApp(String packageName) {List<String> list getBackgroundAliveAppList();if (list ! null && packageName ! null && packageName.length() > 0) {if (!list.co…

牛客ds题1002践踏

分析每个操作 操作一&#xff0c;加入一条线段[l,r],感觉可以直接懒标记&#xff0c;[l,r] tag1&#xff0c;也可以差分操作 操作二&#xff0c;删除一条线段[l,r],[l,r]tag-1 操作三&#xff0c;xkty,问y可以在几条线段内&#xff0c;t取整数&#xff0c;一开始想暴力,r<…

容器运行nslookup提示bash: nslookup: command not found【笔记】

在容器中提示bash: nslookup: command not found&#xff0c;表示容器中没有安装nslookup命令。 可以通过以下命令安装nslookup&#xff1a; 对于基于Debian/Ubuntu的容器&#xff0c;使用以下命令&#xff1a; apt-get update apt-get install -y dnsutils对于基于CentOS/R…

AI网络爬虫:用GraphQL查询爬取动态网页数据

任务&#xff1a;爬取网站www.skillshare.com搜索结果页面数据&#xff1a; 查看网站的请求信息&#xff1a; 请求网址: https://www.skillshare.com/api/graphql 请求方法: POST 状态代码: 200 OK 远程地址: 127.0.0.1:10809 引荐来源网址政策: strict-origin-when-…

一篇文章讲透数据结构之树and二叉树

一.树 1.1树的定义 树是一种非线性的数据结构&#xff0c;它是有n个有限结点组成的一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根在上&#xff0c;叶在下的。 在树中有一个特殊的结点&#xff0c;称为根结点&#xff0c;根结点…

【玩转google云】在 Google Cloud 和 AWS 之间创建高可用性 VPN 连接(一)

目录 一、目标 二、架构:实现高可用性 VPN 连接 1、架构图 2、实现 99.99% 的服务可用性 SLA

免费工具扫描 Linux 中已知威胁

首发公众号网络研究观&#xff0c;关注获取更多。 卡巴斯基为 Linux 平台发布了一款名为 KVRT 的新病毒清除工具&#xff0c;允许用户免费扫描他们的系统并清除恶意软件和其他已知威胁。 尽管人们普遍误以为 Linux 系统本质上是安全的&#xff0c;不会受到威胁&#xff0c;但不…

AIGC工具汇总介绍

AIGC工具汇总介绍 一、引言 随着人工智能技术的飞速发展&#xff0c;AIGC&#xff08;AI Generated Content&#xff09;工具已经成为内容创作领域的重要力量。这些工具利用深度学习、自然语言处理、计算机视觉等AI技术&#xff0c;自动生成各种形式的数字内容&#xff0c;如…

如何使用Vuforia AR进行增强现实技术的开发?

前言 今天是坚持写博客的第17天&#xff0c;很高兴自己可以一直坚持下来。我们今天来讲讲怎么使用Vuforia AR进行增强现实的开发。 我们需要在今天的开发中用到Vuforia AR和2018版的Unity3d 什么是Vuforia AR Vuforia AR是基于实时计算摄影机影像的位置及角度&#xff0c;并…

掘金小册《前端性能优化原理与实践》读书笔记

前端性能优化&#xff1a; 以下文章内容是根据掘金小册《前端性能优化原理与实践》整理的 网络层面的优化 1、减少请求次数&#xff1b;2、减少单次请求花费的时间&#xff1b; webpack相关优化&#xff1b; 1、按需加载关键&#xff1a;require.ensure(dependencies, cal…

Kubernetes ingress

目录 一.ingress 1.ingress简介 2.实现外部应用能访问内部集群服务的方法 &#xff08;1&#xff09;NodePort&#xff1a; &#xff08;2&#xff09;LoadBalancer&#xff1a; &#xff08;3&#xff09;externalIPs&#xff1a; &#xff08;4&#xff09;ingress&am…

vue computed 计算属性

一、计算属性(computed) 1、说明 当一些数据需要根据其它数据变化时,需要进行处理才能去展示,虽然vue提供了绑定数据表达式绑定的方式,但是设计它的初衷只是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护,对于一些比较复杂和特殊的计算有可能就捉襟见肘了,而…