MySQL 迁移 OceanBase 的 Oracle模式中,实现自增主键的方法
本文作者:赵黎明,爱可生 MySQL DBA 团队成员,熟练掌握Oracle、MySQL等数据库系统,擅长对数据库性能问题的诊断,以及事务与锁机制的分析等。负责解决客户在MySQL及爱可生自主研发的DMP平台日常运维中所遇到的各种问题,并且对开源数据库相关的技术抱有浓厚的兴趣。
背景
在将MySQL迁移到OceanBase Oracle模式的过程中,我们经常会面临如何在OB Oracle中实现自增主键的问题。OB社区中已有一些文章为我们提供了相应的解决方案,可以作为我们迁移过程中的参考。
本文将从实践角度出发,验证并总结一个比较可行的实施方案。
方案一
我们将通过创建创建自定义序列的方式来实现自增主键。
MySQL 端创建测试表
zlm@10.186.60.68 [zlm]> desc t;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)zlm@10.186.60.68 [zlm]> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.00 sec)
使用 DBCAT 导出表结构
DBCAT 是 OB 提供的命令行工具,主要用于异构数据库迁移场景中非表对象的 DDL 导出和转换,如: Oracle 中的序列、函数、存储过程、包、触发器、视图等对象。
cd /opt/oceanbase_package/tools/dbcat-1.9.1-RELEASE/bin
./dbcat convert -H 10.186.60.68 -P 3332 --user=zlm --password=zlm --database=zlm --no-schema --no-quote --from mysql57 --to oboracle32x --table t --file=/tmp
Parsed args:
[--no-quote] true
[--no-schema] true
[--table] [t]
[--host] 10.186.60.68
[--port] 3332
[--user] zlm
[--password] ******
[--database] zlm
[--file] /tmp
[--from] mysql57
[--to] oboracle32x
2023-08-16 14:41:58 INFO Init convert config finished.
2023-08-16 14:41:58 INFO {dataSource-1} inited
2023-08-16 14:41:58 INFO Init source druid connection pool finished.
2023-08-16 14:41:58 INFO Register c.o.o.d.m.c.m.MySql56ObOracle22xColumnConverter
2023-08-16 14:41:58 INFO Register c.o.o.d.m.c.m.MySql56ObOracle22xIndexConverter
2023-08-16 14:41:58 INFO Register c.o.o.d.m.c.m.MySql56ObOracle22xPrimaryKeyConverter
2023-08-16 14:41:58 INFO Register c.o.o.d.m.c.m.MySql56ObOracle22xUniqueKeyConverter
2023-08-16 14:41:58 INFO Register c.o.o.d.m.c.m.MySql56ObOracle22xPartitionConverter
2023-08-16 14:41:59 INFO Load meta/mysql/mysql56.xml, meta/mysql/mysql57.xml successed
2023-08-16 14:42:09 INFO Query 0 dependencies elapsed 17.35 ms
2023-08-16 14:42:09 INFO Query table: "t" attr finished. Remain: 0
2023-08-16 14:42:09 INFO Query 1 tables elapsed 69.71 ms
2023-08-16 14:42:09 WARN Include types is empty. Ignore schema: ZLM
2023-08-16 14:42:09 WARN Skip to compare/convert sequences as SEQUENCE is unsupported
2023-08-16 14:42:09 INFO Starting to convert schema to path: "/tmp/dbcat-2023-08-16-144209/ZLM"
2023-08-16 14:42:09 INFO Successed to generate report in the path: "/tmp/dbcat-2023-08-16-144209/ZLM-conversion.html"
2023-08-16 14:42:09 INFO {dataSource-1} closing ...
2023-08-16 14:42:09 INFO {dataSource-1} closed
cd /tmp/dbcat-2023-08-16-144209/ZLM
cat TABLE-schema.sql
CREATE TABLE t (id NUMBER(19,0),name VARCHAR2(30 BYTE),CONSTRAINT PRIMARY PRIMARY KEY (id)
);-- CREATE SEQUENCE xxx START WITH 1 INCREMENT BY 1 ... for t
DBCAT 会对目标表的表结构做转换,使其符合 Oracle 的语法,并在导出的 DDL 语句中写入一行创建序列的伪 SQL ,可见,此工具也是建议创建序列来处理 MySQL 自增列的。
在 OB 目标端创建序列
- 对于含有自增列的每个表,都需要创建一个序列与之对应。
- 创建序列时,建议以
SEQ_<表名>_<字段名>的方式命名。 - 当不指定序列的
CYCLE和 ORDER 属性时,其默认值都是 N ,即:不循环,不排序。 - 当不指定序列的 CACHE 属性时,默认缓存 20 个序列。
- 字段
MIN_VALUE对应创建序列时 MIN_VALUE 属性的值。 - 字段
LAST_NUMBER对应创建序列时 START WITH 属性的值。
ZLM[ZLM]> CREATE SEQUENCE SEQ_T_ID MINVALUE 1 MAXVALUE 999999 INCREMENT BY 1 START WITH 1;
Query OK, 0 rows affected (0.03 sec)ZLM[ZLM]> SELECT SEQUENCE_NAME,MIN_VALUE,LAST_NUMBER,CYCLE_FLAG,ORDER_FLAG,CACHE_SIZE FROM DBA_SEQUENCES WHERE SEQUENCE_OWNER='ZLM';
+---------------+-----------+-------------+------------+------------+------------+
| SEQUENCE_NAME | MIN_VALUE | LAST_NUMBER | CYCLE_FLAG | ORDER_FLAG | CACHE_SIZE |
+---------------+-----------+-------------+------------+------------+------------+
| SEQ_T_ID | 1 | 1 | N | N | 20 |
+---------------+-----------+-------------+------------+------------+------------+1 row in set (0.01 sec)ZLM[ZLM]> drop sequence SEQ_T_ID;
Query OK, 0 rows affected (0.03 sec)ZLM[ZLM]> CREATE SEQUENCE SEQ_T_ID MINVALUE 1 MAXVALUE 999999 INCREMENT BY 1 START WITH 10;
Query OK, 0 rows affected (0.03 sec)ZLM[ZLM]> SELECT SEQUENCE_NAME,MIN_VALUE,LAST_NUMBER,CYCLE_FLAG,ORDER_FLAG,CACHE_SIZE FROM DBA_SEQUENCES WHERE SEQUENCE_OWNER='ZLM';
+---------------+-----------+-------------+------------+------------+------------+
| SEQUENCE_NAME | MIN_VALUE | LAST_NUMBER | CYCLE_FLAG | ORDER_FLAG | CACHE_SIZE |
+---------------+-----------+-------------+------------+------------+------------+
| SEQ_T_ID | 1 | 10 | N | N | 20 |
+---------------+-----------+-------------+------------+------------+------------+1 row in set (0.03 sec)
在 OB 目标端建表
基于第 1 步获取的 DDL 和第 2 步创建的序列。
ZLM[ZLM]> CREATE TABLE "ZLM"."T" (-> "ID" NUMBER(19,0) DEFAULT SEQ_T_ID.NEXTVAL,-> "NAME" VARCHAR2(30 BYTE),-> CONSTRAINT "PRIMARY" PRIMARY KEY ("ID"));
Query OK, 0 rows affected (0.15 sec)
通常表结构及数据都是通过 OMS 来完成迁移的,很少会直接用 DBCAT 生成的 DDL 建表语句去目标端手动建表,除了一些较特殊的场景,如以上这种给字段增加缺省属性为序列值情况。
建表时注意:应将表名和字段名都改为大写,因为 Oracle 中严格区分数据库对象的大小写。ID 列的 DEFAULT 值,指定为第 2 步所创建序列的下一个值,即:SEQ_T_ID.NEXTVAL
使用 DataX 迁移数据
DataX 是阿里开源的离线数据同步工具,支持多种异构数据源,可以通过 OB 的 Reader 和 Writer 插件实现 OB 与异构数据库之间的数据迁移。
-- 创建 DataX 配置文件(存放在 dataX 的 ./job 目录下)
cat t.json
{"job": {"setting": {"speed": {"channel": 4 },"errorLimit": {"record": 0,"percentage": 0.1}},"content": [{"reader": {"name": "mysqlreader","parameter": {"username": "zlm","password": "zlm","column": ["*"],"connection": [{"table": ["t"],"jdbcUrl": ["jdbc:mysql://10.186.60.68:3332/zlm?useUnicode=true&characterEncoding=utf8"]}]}},"writer": {"name": "oceanbasev10writer","parameter": {"obWriteMode": "insert","column": ["*"],"preSql": ["truncate table T"],"connection": [{"jdbcUrl": "||_dsc_ob10_dsc_||jingbo_ob:ob_oracle||_dsc_ob10_dsc_||jdbc:oceanbase://10.186.65.22:2883/ZLM?useLocalSessionState=true&allowBatch=true&allowMultiQueries=true&rewriteBatchedStatements=true","table": ["T"]}],"username": "ZLM","password":"zlm","writerThreadCount":10,"batchSize": 1000,"memstoreThreshold": "0.9"}}}]}
}-- 执行数据迁移
./bin/datax.py job/t.json
DataX (20220610-external), From Alibaba !
Copyright (C) 2010-2017, Alibaba Group. All Rights Reserved.
full db is not specified.
schema sync is not specified.
java -server -Xms4g -Xmx16g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/datax3/log -DENGINE_VERSION=20220610-external -Xms4g -Xmx16g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/datax3/log -Dloglevel=info -Dproject.name=di-service -Dfile.encoding=UTF-8 -Dlogback.statusListenerClass=ch.qos.logback.core.status.NopStatusListener -Djava.security.egd=file:///dev/urandom -Ddatax.home=/home/admin/datax3 -Dlogback.configurationFile=/home/admin/datax3/conf/logback.xml -classpath /home/admin/datax3/lib/*:. -Dlog.file.name=in_datax3_job_t_json com.alibaba.datax.core.Engine -mode standalone -jobid -1 -job /home/admin/datax3/job/t.json -fulldb false -schema false
2023-08-16 14:58:41.088 [main] INFO Engine - running job from /home/admin/datax3/job/t.json
2023-08-16 14:58:41.374 [main] INFO VMInfo - VMInfo# operatingSystem class => sun.management.OperatingSystemImpl
2023-08-16 14:58:41.382 [main] INFO Engine - the machine info =>
略...2. record average count and max count task info :
PHASE | AVERAGE RECORDS | AVERAGE BYTES | MAX RECORDS | MAX RECORD`S BYTES | MAX TASK ID | MAX TASK INFO
READ_TASK_DATA | 3 | 6B | 3 | 6B | 0-0-0 | t,jdbcUrl:[jdbc:mysql://10.186.60.68:3332/zlm]
2023-08-16 14:58:45.189 [job-0] INFO MetricReportUtil - reportJobMetric is turn off
2023-08-16 14:58:45.189 [job-0] INFO StandAloneJobContainerCommunicator - Total 3 records, 6 bytes | Speed 3B/s, 1 records/s | Error 0 records, 0 bytes | All Task WaitWriterTime 0.000s | All Task WaitReaderTime 0.000s | Percentage 100.00%
2023-08-16 14:58:45.190 [job-0] INFO LogReportUtil - report datax log is turn off
2023-08-16 14:58:45.190 [job-0] INFO JobContainer -
任务启动时刻 : 2023-08-16 14:58:41
任务结束时刻 : 2023-08-16 14:58:45
任务总计耗时 : 3s
任务平均流量 : 3B/s
记录写入速度 : 1rec/s
读出记录总数 : 3
读写失败总数 : 0
2023-08-16 14:58:45.190 [job-0] INFO PerfTrace - reset PerfTrace.
验证效果
验证主键列能否实现自增。
SYS[ZLM]> select * from t;
+----+------+
| ID | NAME |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.01 sec)SYS[ZLM]> insert into t(name) values('d');
Query OK, 1 row affected (0.02 sec)SYS[ZLM]> select * from t;
+----+------+
| ID | NAME |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
+----+------+
4 rows in set (0.00 sec)
新插入的数据每次都会先获取 ID 列上序列的 NEXTVAL 值,于是就实现了主键自增的需求。
使用自定义序列的 NEXTVAL 作为主键列的 DEFAULT 值后,不必关心源端表上记录的自增列最大值,将表迁移过去后,直接插入新数据时,不会与原来的数据冲突。
方案二
利用 GENERATED BY DEFAULT AS IDENTITY 属性生成序列的方案是否好用?先来看一个测试吧!
-- 删除并重建测试表
ZLM[ZLM]> DROP TABLE T;
Query OK, 0 rows affected (0.10 sec)
ZLM[ZLM]> CREATE TABLE "ZLM"."T" (-> "ID" NUMBER(19,0) GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 999999,-> "NAME" VARCHAR2(30 BYTE),-> CONSTRAINT "PRIMARY" PRIMARY KEY ("ID"));
Query OK, 0 rows affected (0.15 sec)-- 查看序列
ZLM[ZLM]> SELECT SEQUENCE_NAME,MIN_VALUE,LAST_NUMBER,CYCLE_FLAG,ORDER_FLAG,CACHE_SIZE FROM DBA_SEQUENCES WHERE SEQUENCE_OWNER='ZLM';
+-----------------+-----------+-------------+------------+------------+------------+
| SEQUENCE_NAME | MIN_VALUE | LAST_NUMBER | CYCLE_FLAG | ORDER_FLAG | CACHE_SIZE |
+-----------------+-----------+-------------+------------+------------+------------+
| SEQ_T_ID | 1 | 21 | N | N | 20 |
| ISEQ$$_50034_16 | 1 | 1 | N | N | 20 |
+-----------------+-----------+-------------+------------+------------+------------+
2 rows in set (0.00 sec)# 此时,系统自动创建了名为 ISEQ$$_50034_16 的序列,其他默认值与自定义创建的序列一致-- 查看表结构
ZLM[ZLM]> desc t;
+-------+--------------+------+-----+------------------+-------+
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
+-------+--------------+------+-----+------------------+-------+
| ID | NUMBER(19) | NO | PRI | SEQUENCE.NEXTVAL | NULL |
| NAME | VARCHAR2(30) | YES | NULL| NULL | NULL |
+-------+--------------+------+-----+------------------+-------+
2 rows in set (0.02 sec)# 注意,ID 列的 DEFAULT 值为 SEQUENCE.NEXTVAL ,而不是 ISEQ$$_50034_16.NEXTVAL-- 重新导入数据
./bin/datax.py job/t.json
略 ...-- 插入数据
ZLM[ZLM]> insert into t(name) values('d');
ORA-00001: unique constraint '1' for key 'PRIMARY' violatedZLM[ZLM]> insert into t(name) values('d');
ORA-00001: unique constraint '2' for key 'PRIMARY' violatedZLM[ZLM]> insert into t(name) values('d');
ORA-00001: unique constraint '3' for key 'PRIMARY' violatedZLM[ZLM]> insert into t(name) values('d');
Query OK, 1 row affected (0.01 sec)ZLM[ZLM]> select "ISEQ$$_50034_16".CURRVAL from dual;
+---------+
| CURRVAL |
+---------+
| 4 |
+---------+1 row in set (0.00 sec)
表中有 3 条数据,当执行插入时,START WITH 实际上还是从默认值 1 开始的。
每次执行插入,ID 都会获取序列的 NEXTVAL 值,直到执行至第 4 次,未与表中已有记录冲突,才能插入成功。
对于这种场景,解决方案有两种,不过都比较繁琐:
- 插入记录前先获取当前序列的 NEXTVAL 值(需多次执行,执行次数 = 源端表记录数)。
- 创建序列时根据源端表上自增列最大值来指定 START WITH 属性。
注意:使用 GENERATED BY DEFAULT AS IDENTITY 属性生成的序列无法直接删除,会报错。ORA-32794: cannot drop a system-generated sequence
获取表中自增列最大值
方法 1:MAX 函数
zlm@10.186.60.68 [zlm]> SELECT MAX(id)+1 as AUTO_INCREMENT FROM t;
+----------------+
| AUTO_INCREMENT |
+----------------+
| 4 |
+----------------+1 row in set (0.00 sec)
方法 2:系统视图
zlm@10.186.60.68 [zlm]> select AUTO_INCREMENT from information_schema.tables where table_name='t';
+----------------+
| AUTO_INCREMENT |
+----------------+
| 4 |
+----------------+1 row in set (0.00 sec)
方法3:show create table 命令
zlm@10.186.60.68 [zlm]> show create table t\G
*************************** 1. row ***************************Table: t
Create Table: CREATE TABLE `t` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(10) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
脚本初始化序列的一个示例
-- 删除并重建表
ZLM[ZLM]> drop table t;
Query OK, 0 rows affected (0.02 sec)ZLM[ZLM]> CREATE TABLE "ZLM"."T" (-> "ID" NUMBER(19,0) GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 999999,-> "NAME" VARCHAR2(30 BYTE),-> CONSTRAINT "PRIMARY" PRIMARY KEY ("ID"));
Query OK, 0 rows affected (0.04 sec)-- 导入数据
./bin/datax.py job/t.json
略 ...-- 执行脚本并确认返回结果正常
[root@10-186-65-73 ~]# cat init_sequence.sh
#!/bin/bash## 获取当前表自增列最大值
i=$(obclient -h10.186.60.68 -P3332 -uzlm -pzlm -Nse "SELECT MAX(id)+1 FROM zlm.t;" 2>/dev/null | head -1)## 循环执行SQL初始化序列值
for ((j=1; j<=$i; j++))
doobclient -h10.186.65.43 -P2883 -uZLM@ob_oracle#bobo_ob:1675327512 -pzlm -A -c -DZLM -Nse "select ISEQ\$\$_50037_16.nextval from dual;" 1>/dev/null 2>&1
done
[root@10-186-65-73 ~]# sh init_sequence.sh
[root@10-186-65-73 ~]# echo $?
0-- 执行插入
ZLM[ZLM]> insert into t(name) values('d');
Query OK, 1 row affected (0.01 sec)
序列经过初始化处理后,当完成数据导入并直接插入新增记录时,就不会再产生唯一性冲突的报错了。同样地,先用脚本获取到自增列的最大值,在创建序列时指定 START WITH 与自增列最大值一致,也可以解决以上问题,这里不展开了。
总体而言,GENERATED BY DEFAULT AS IDENTITY 属性创建(方案二)的序列不如自定义序列(方案一)好用。
总结
本文验证并阐述了在 OB Oracle 中实现自增主键的两种方法:创建自定义序列和利用 GENERATED BY DEFAULT AS IDENTITY 属性生成序列。
方案一
创建自定义序列的时,需要为每张有自增列的表创建一个单独的序列,序列名建议与表名关联,但无需关注 START WITH 的取值。当插入新记录时,会自动去获取下一个可用的序列值。
方案二
利用 GENERATED BY DEFAULT AS IDENTITY 属性生成序列时,存在一些限制:
- 因序列由系统自动创建并管理,需要查询系统视图才能获取序列名,无法与业务表名对应。
- 创建序列时需要根据自增列最大值来指定 START WITH 的取值,当有大量表需要处理时,较繁琐。
利用 GENERATED BY DEFAULT AS IDENTITY 属性生成的序列名,在内部有一个计数器,会累计增加,即使删除了原来的序列,原有的名字也不会被重用。删除表时,会自动清理由 GENERATED BY DEFAULT AS IDENTITY 属性生成的序列(直接删除该序列会报错),但不会影响之前创建的其他自定义序列。
采用 GENERATED BY DEFAULT AS IDENTITY 属性生成序列的方案时,还要额外考虑源端待迁移表当前自增列最大值的问题,这无疑增加了迁移的复杂度。
综上所述,更推荐使用自定义序列实现自增主键的方案。
相关文章:
MySQL 迁移 OceanBase 的 Oracle模式中,实现自增主键的方法
本文作者:赵黎明,爱可生 MySQL DBA 团队成员,熟练掌握Oracle、MySQL等数据库系统,擅长对数据库性能问题的诊断,以及事务与锁机制的分析等。负责解决客户在MySQL及爱可生自主研发的DMP平台日常运维中所遇到的各种问题&a…...
【C++ 面试 - 基础题】每日 3 题(十一)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏&…...
ESP8266在线升级OTA固件
OTA的基本实现方式: ESP8266 的 OTA 实现有几种方式,常用的方式包括: 1、Arduino OTA:使用Arduino IDE提供的OTA功能,可以直接通过Arduino IDE上传固件到ESP8266。 2、Web OTA:ESP8266运行一个简易的Web服…...
精通C++ STL(六):list的模拟实现
目录 类及其成员函数接口总览 结点类的模拟实现 构造函数 迭代器类的模拟实现 迭代器类存在的意义 迭代器类的模板参数说明 构造函数 运算符的重载 --运算符的重载 运算符的重载 !运算符的重载 *运算符的重载 ->运算符的重载 list的模拟实现 默认成员函数 构造函数 拷贝…...
《雅思口语真经总纲1.0》话题实战训练笔记part1——6. Music
《雅思口语真经总纲1.0》笔记——第四章:口语素材大全(part1、part2、part3回答准则及练习方法,不包括范例答案)★★★★★ 文章目录 MusicWhen do you listen to music?20240804答评价注意事项1、在说到“no music”时ÿ…...
Python之赋值语句(多重赋值和交换赋值)
这是《Python入门经典以解决计算问题为导向的Python编程实践》73-74页关于赋值的内容。讲了Python中几种赋值方式。 赋值语句 1、最简单的赋值:ab2、多重赋值:a,b,c1,2,33、交换:a,bb,a 1、最简单的赋值:ab b可以是数字、字符串…...
网络协议七 应用层 HTTP 协议
应用层常见的协议 HTTP协议 1. 如何查看我们的http 协议全部的内容有哪些呢? 一种合理的方法是 通过 wireshark 软件,找到想要查看的HTTP --->追踪流--->HTTP流 来查看 结果如下:红色部分 为 发送给服务器的,蓝色部分为服务…...
uniapp vue 在适配百度小程序平台动态:style
uniapp vue 在适配百度小程序平台动态:style踩坑报错Unexpected string concatenation of literals 抖快平台动态style写法基本是 <view :style"{width: 686rpx, height: (setHeight 96) rpx}"> </view>这种写法在百度上会又解析报错: Une…...
【最小生成树】(二) Kruskal 算法
题目: 寻宝 题目描述 在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。 不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案…...
haproxy最强攻略
1、负载均衡 负载均衡(Load Balance,简称 LB)是高并发、高可用系统必不可少的关键组件,目标是 尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性。 负载均衡的主要作用如下: 高并发…...
XetHub 加入 Hugging Face!
我们非常激动地正式宣布,Hugging Face 已收购 XetHub 🔥 XetHub 是一家位于西雅图的公司,由 Yucheng Low、Ajit Banerjee 和 Rajat Arya 创立,他们之前在 Apple 工作,构建和扩展了 Apple 的内部机器学习基础设施。XetH…...
在编程学习的海洋中,如何打造高效的知识宝库
目录 在编程学习的海洋中,如何打造高效的知识宝库一、笔记记录的重要性:为知识设立灯塔二、快速记录的策略:抓住知识的核心三、系统化的整理:构建个人知识体系四、实用工具推荐:为知识管理添砖加瓦五、保持条理性的秘诀…...
string详解(1)
1.C语言中的字符串 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理&…...
Linux云计算 |【第二阶段】NETWORK-DAY4
主要内容: NAT 原理与配置(私有IP地址、静态NAT转换、Easy IP)、VRRP解析(主路由器、备份路由器、虚拟路由器、优先级) 一、NAT概述 NAT 网络地址转换(Network Address Translation)是一种网络…...
amazon linux使用密码登录或者root登陆
1. 首先要把创建root密码,如果原来的密码不记得了,可以直接用 sudo passwd -d root 删除原来的密码 然后创建root密码 sudo passwd root 2. 修改 sshd_config 文件 vim /etc/ssh/sshd_config 允许使用密码登录 PasswordAuthentication yes 允许root…...
集智书童 | CNN 与 Transformer 的强强联合:AResNet-ViT在图像分析中的优势 !
本文来源公众号“集智书童”,仅用于学术分享,侵权删,干货满满。 原文链接:CNN 与 Transformer 的强强联合:AResNet-ViT在图像分析中的优势 ! 作者针对残差CNN分支的注意力引导设计进行了消融实验。同时&a…...
Ubuntu基础使用指南
Ubuntu基础使用指南 Ubuntu作为一款流行的开源操作系统,以其稳定性、安全性和易用性著称。无论是作为服务器操作系统还是桌面操作系统,Ubuntu都能满足用户的各种需求。下面,我们将从Ubuntu的基础使用开始,带你深入了解这个强大的…...
怎样才算精通 Excel?
最强AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ 高赞回答很系统,但普通人这么学,没等精通先学废了! 4年前,我为了学数据分析&#…...
怎么学算法并找到工作
1.基础 找一本基础的内容看一遍 时间复杂度、空间复杂度计算方式数组、队列、栈、树、图结构十大排序算法 2.《hello算法》 动画图解算法 https://www.hello-algo.com/chapter_hello_algo/ 3.《剑指Offer》 一些面试的高频有年度的题解 里么的题很有特色,而…...
【实时建图】MapTR(1)------ 论文详解
作者们提出了一种有效构建高清地图的方法(MapTR),该地图为自动驾驶系统的规划提供丰富且精确的环境信息。这是一种结构化端到端变换器,用于高效在线矢量化地图构建。作者提出了一种统一的置换等价建模方法,即将地图元素建模为一个具有一组等价置换的点集,这准确地描述了地…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
