【canal 中间件】canal 实时监听 binlog
文章目录
- 一、安装 MySQL
- 1.1 启动 mysql 服务器
- 1.2 开启 Binlog 写入功能
- 1.2.1创建 binlog 配置文件
- 1.2.2 修改配置文件权限
- 1.2.3 挂载配置文件
- 1.2.4 检测 binlog 配置是否成功
- 1.3 创建账户并授权
- 二、安装 canal
- 2.1 安装 canal-admin(可选)
- 2.1.1 启动 canal-admin 容器
- 2.1.2 访问页面
- 2.2 安装 canal-server
- 2.2.1 启动 canal 容器
- 2.2.2 查看启动日志
- 三、客户端代码
- 3.1 导入依赖
- 3.2 简单案例代码
- 四、测试
- 4.1 创建数据库及表
- 4.2 插入数据
- 4.3 更新数据
- 参考资料
完整案例代码:java-demos/middleware-demos/spring-boot-canal at main · idealzouhu/java-demos
一、安装 MySQL
QuickStart · alibaba/canal Wiki (github.com)
1.1 启动 mysql 服务器
docker run --name mysql-canal ^
-p 3306:3306 ^
-e MYSQL_ROOT_PASSWORD=root ^
-d mysql:5.7.36
1.2 开启 Binlog 写入功能
对于自建 MySQL容器 , 我们需要开启 Binlog 写入功能。
1.2.1创建 binlog 配置文件
在宿主机上创建 my.cnf
文件,配置 binlog-format 为 ROW 模式。my.cnf
的配置内容如下:
[mysqld]
# 开启 binlog
log-bin=mysql-bin
# 选择 ROW 模式
binlog-format=ROW
# 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
server_id=1
1.2.2 修改配置文件权限
进入 MySQL 容器并修改 MySQL 容器配置文件 /etc/mysql/my.cnf
权限,以避免权限警告:
# 进入 MySQL 容器
$ docker exec -it mysql-canal bash# 修改文件权限
$ chmod 644 /etc/mysql/my.cnf
$ exit
注意,在没有修改配置文件并启动 MySQL 容器情况下,MySQL 会警告配置文件 /etc/mysql/my.cnf
权限设置不当,允许所有用户写入(world-writable)。由于安全原因,MySQL 会忽略这个配置文件。
[Warning] World-writable config file '/etc/mysql/my.cnf' is ignored.
1.2.3 挂载配置文件
在 MySQL 容器运行后,使用以下命令将创建的 my.cnf
文件挂载到容器内的 /etc/mysql/my.cnf
:
# 将本地的 my.cnf 文件复制到容器的指定目录下
$ docker cp D:\Learning\java-demos\middleware-demos\spring-boot-canal\src\main\resources\conf\my.cnf mysql-canal:/etc/mysql/# 为了使新的配置生效,重启 MySQL 容器
$ docker restart mysql-canal
注意,MySQL 容器的 /etc/mysql/my.cnf
是一个符号链接,直接指定完整路径时会导致问题。
MySQL 启动时会首先加载主配置文件
/etc/mysql/my.cnf
,然后加载conf.d
目录下的所有配置文件。
1.2.4 检测 binlog 配置是否成功
进入 MySQL, 利用 show variables like 'log_bin';
查看是否打开 binlog 模式:
$ docker exec -it mysql-canal bash# 查看挂载后的 my.cnf 文件
$ tail /etc/mysql/my.cnf# 查看 binlog 是否开启
$ mysql -uroot -proot
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.01 sec)# 查看 binlog 日志文件列表
mysql> show binary logs;# 查看正在写入的 binlog 文件
mysql> show master status;# 查看 Binlog 文件内容
mysql> mysqlbinlog /var/lib/mysql/mysql-bin.000001
1.3 创建账户并授权
授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant
# 进入 mysql 容器
$ docker exec -it mysql-canal mysql -uroot -proot# 创建用户名和密码都为 canal 的账户
mysql> CREATE USER canal IDENTIFIED BY 'canal';# 授予权限 GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
mysql> GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
二、安装 canal
canal-server 和 canal-admin 在 Docker 里面的详细教程查看 Docker QuickStart · alibaba/canal Wiki 和 Canal Admin Docker · alibaba/canal Wiki。
2.1 安装 canal-admin(可选)
2.1.1 启动 canal-admin 容器
$ docker pull canal/canal-admin:v1.1.7$ docker run -d ^
--name canal-admin ^
--privileged=true ^
--restart always ^
-p 8089:8089 ^
-e server.port=8089 ^
-e canal.adminUser=admin ^
-e canal.adminPasswd=admin ^
-m 512m ^
canal/canal-admin:v1.1.7
在 canal 启动成功后,查看 admin 日志
2024-10-28 21:35:01 DOCKER_DEPLOY_TYPE=VM
2024-10-28 21:35:01 ==> INIT /alidata/init/02init-sshd.sh
2024-10-28 21:35:01 ==> EXIT CODE: 0
2024-10-28 21:35:01 ==> INIT /alidata/init/fix-hosts.py
2024-10-28 21:35:01 ==> EXIT CODE: 0
2024-10-28 21:35:01 ==> INIT DEFAULT
2024-10-28 21:35:01 ==> INIT DONE
2024-10-28 21:35:01 ==> RUN /home/admin/app.sh
2024-10-28 21:35:01 ==> START ...
2024-10-28 21:35:01 Failed to get D-Bus connection: Operation not permitted
2024-10-28 21:35:01 Failed to get D-Bus connection: Operation not permitted
2024-10-28 21:35:01 start mysql ...
2024-10-28 21:35:10 mysql: [Warning] Using a password on the command line interface can be insecure.
2024-10-28 21:35:10 start mysql successful
2024-10-28 21:35:10 start admin ...
2024-10-28 21:35:15 start canal successful
2024-10-28 21:35:15 ==> START SUCCESSFUL ...
2.1.2 访问页面
访问 http://127.0.0.1:8089/ ,默认账号密码为 admin/123456
2.2 安装 canal-server
2.2.1 启动 canal 容器
$ docker pull canal/canal-server:v1.1.7$ docker run -d ^--name canal-server ^--restart always ^-p 11111:11111 ^--privileged=true ^-e canal.destinations=test ^-e canal.instance.mysql.slaveId=1234 ^-e canal.instance.master.address=172.17.0.4:3306 ^-e canal.instance.dbUsername=canal ^-e canal.instance.dbPassword=canal ^-e canal.instance.connectionCharset=UTF-8 ^-e canal.instance.tsdb.enable=true ^-e canal.instance.gtidon=false ^-e canal.instance.filter.regex=.\*\\\\..\* ^-m 4096m ^canal/canal-server:v1.1.7
2.2.2 查看启动日志
在 canal 启动成功后,查看启动日志
2024-10-28 21:29:00 DOCKER_DEPLOY_TYPE=VM
2024-10-28 21:29:00 ==> INIT /alidata/init/02init-sshd.sh
2024-10-28 21:29:00 ==> EXIT CODE: 0
2024-10-28 21:29:00 ==> INIT /alidata/init/fix-hosts.py
2024-10-28 21:29:00 ==> EXIT CODE: 0
2024-10-28 21:29:00 ==> INIT DEFAULT
2024-10-28 21:29:00 ==> INIT DONE
2024-10-28 21:29:00 ==> RUN /home/admin/app.sh
2024-10-28 21:29:01 ==> START ...
2024-10-28 21:29:01 start canal ...
2024-10-28 21:29:00 Failed to get D-Bus connection: Operation not permitted
2024-10-28 21:29:00 Failed to get D-Bus connection: Operation not permitted
2024-10-28 21:29:36 start canal successful
2024-10-28 21:29:36 ==> START SUCCESSFUL ...
看到 successful 之后,就代表 canal-server 启动成功,然后就可以在 canal-admin 上进行任务分配了。
三、客户端代码
3.1 导入依赖
创建 Spring Boot 项目,并导入以下依赖。
<dependency><groupId>com.alibaba.otter</groupId><artifactId>canal.client</artifactId><version>1.1.7</version>
</dependency><!-- Message、CanalEntry.Entry等来自此安装包 -->
<dependency><groupId>com.alibaba.otter</groupId><artifactId>canal.protocol</artifactId><version>1.1.7</version>
</dependency>
3.2 简单案例代码
编写简单的案例打印 canal server 解析 binlog 获得的实体类信息, 具体代码如下:
public class SimpleCanalClientExample {/*** 主函数入口* <p>* 建立与Canal服务器的连接,订阅数据库变化,并处理接收到的消息* </p>** @param args 命令行参数*/public static void main(String[] args) {// 创建链接CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("127.0.0.1",11111), "test", "", "");// 批处理大小,即每次获取的最大消息数量int batchSize = 1000;// 连续接收到空消息的次数int emptyCount = 0;try {// 建立连接connector.connect();// 订阅所有数据库和表的变化connector.subscribe(".*\\..*");// 回滚到未确认的消息connector.rollback();// 最大连续接收到空消息的次数int totalEmptyCount = 1200;// 循环获取消息,直到连续接收到空消息的次数超过totalEmptyCountwhile (emptyCount < totalEmptyCount) {// 获取指定数量的数据Message message = connector.getWithoutAck(batchSize);// 获取消息IDlong batchId = message.getId();// 获取消息中的数据条目数量int size = message.getEntries().size();// 如果消息ID为-1或数据条目数量为0,则增加空消息计数if (batchId == -1 || size == 0) {emptyCount++;System.out.println("empty count : " + emptyCount);// 空消息过多时休眠1秒try {Thread.sleep(1000);} catch (InterruptedException e) {}} else {// 如果接收到数据,则重置空消息计数emptyCount = 0;// 打印接收到的消息信息// System.out.printf("message[batchId=%s,size=%s] \n", batchId, size);printEntry(message.getEntries());}// 提交确认connector.ack(batchId);// 处理失败, 回滚数据// connector.rollback(batchId);}// 如果连续接收到的空消息次数过多,则退出System.out.println("empty too many times, exit");} finally {// 断开连接connector.disconnect();}}/*** 打印 canal server 解析 binlog 获得的实体类信息* <p>* 遍历给定的 entry 列表,解析并打印每个 entry 的详细信息除非 entry 类型是事务开始或结束* 对于非事务 entry,解析其存储值为 RowChange 对象,并根据事件类型打印变更信息* </p>** @param entrys 条目列表,代表一系列数据库变更事件*/private static void printEntry(List<Entry> entrys) {for (Entry entry : entrys) {// 跳过事务开始和事务结束的 entryif (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {continue;}RowChange rowChage = null;try {// 从 entry 的存储值中解析出 RowChange 对象rowChage = RowChange.parseFrom(entry.getStoreValue());} catch (Exception e) {// 如果解析失败,抛出运行时异常,并提供错误信息和原始异常throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),e);}// 获取事件类型,并打印 entry 的基本信息EventType eventType = rowChage.getEventType();System.out.println(String.format("================> binlog[%s:%s] , name[%s,%s] , eventType : %s",entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),eventType));// 遍历 RowChange 中的所有行数据,并根据事件类型打印相应的列信息for (RowData rowData : rowChage.getRowDatasList()) {switch (eventType) {case DELETE:// 对于删除事件,打印行数据的"之前"状态printColumn(rowData.getBeforeColumnsList());break;case UPDATE:// 对于插入事件,打印行数据的"之后"状态printColumn(rowData.getAfterColumnsList());break;default:// 对于其他事件类型,打印行数据的"之前"和"之后"状态System.out.println("-------> before");printColumn(rowData.getBeforeColumnsList());System.out.println("-------> after");printColumn(rowData.getAfterColumnsList());}}}}/*** 打印列信息* 此方法接收一个Column对象列表作为参数,并遍历该列表,将每个Column对象的名称、值和更新状态打印到控制台* 主要用途是用于调试或日志记录,以直观地展示每个列的信息及其更新状态** @param columns Column对象列表,包含要打印的列信息每个Column对象都应提供getName、getValue和getUpdated方法*/private static void printColumn(List<Column> columns) {// 遍历Column对象列表for (Column column : columns) {// 打印每个Column对象的名称、值和更新状态System.out.println(column.getName() + " : " + column.getValue() + " update=" + column.getUpdated());}}
}
四、测试
4.1 创建数据库及表
数据库变更:
CREATE DATABASE test_db;
USE test_db;
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),email VARCHAR(100)
);
控制台输出:
================> binlog[mysql-bin.000004:1234] , name[test_db,] , eventType : QUERY
================> binlog[mysql-bin.000004:219] , name[test,users] , eventType : CREATE
4.2 插入数据
插入语句:
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
控制台输出:
================> binlog[mysql-bin.000004:595] , name[test,users] , eventType : INSERT
id : 1 update=true
name : Alice update=true
email : alice@example.com update=true================> binlog[mysql-bin.000004:883] , name[test,users] , eventType : INSERT
id : 2 update=true
name : Bob update=true
email : bob@example.com update=true
4.3 更新数据
更新语句:
UPDATE users SET email = 'newemail@example.com' WHERE name = 'Bob';
控制台输出:
================> binlog[mysql-bin.000004:2370] , name[test_db,users] , eventType : UPDATE
id : 2 update=false
name : Bob update=false
email : newemail@example.com update=true
参考资料
ClientExample · alibaba/canal Wiki
超详细的canal入门,看这篇就够了-阿里云开发者社区 (aliyun.com)
【Canal】Canal Admin Docker部署 - H__D - 博客园
相关文章:

【canal 中间件】canal 实时监听 binlog
文章目录 一、安装 MySQL1.1 启动 mysql 服务器1.2 开启 Binlog 写入功能1.2.1创建 binlog 配置文件1.2.2 修改配置文件权限1.2.3 挂载配置文件1.2.4 检测 binlog 配置是否成功 1.3 创建账户并授权 二、安装 canal2.1 安装 canal-admin(可选)2.1.1 启动 canal-admin 容器2.1.2 …...
JVM垃圾收集算法、对应收集器和选择建议
如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。 到目前为止还没有最好的垃圾收集器出现,也没万能的垃圾收集器。实际使用中,根据具体应用场景选择合适的垃圾收集器。 1、垃圾收集算法 垃圾收集算法可以从高…...

如何在算家云搭建Aatrox-Bert-VITS2(音频生成)
一、模型介绍 Aatrox - Bert -VITS2 模型是一种基于深度学习的语音合成系统,结合了 BERT 的预训练能力和 VITS2 的微调技术,旨在实现高质量的个性化语音合成。 二、模型搭建流程 1. 创建容器实例 进入算家云的“应用社区”,点击搜索找到…...
ceph灾备之cephfs snapshot mirror和rsync对比
背景 最近要做ceph集群之间的灾备功能,主要讨论文件存储,因为ceph集群容量越来越大,接入的业务也越来越多,一旦出现故障,恢复时间都是小时级(根据经验每年都会出现几次这种事故),对于核心业务无法接受&…...

【工具分享】Plutocrypt勒索病毒解密工具
前言 Plutocrypt勒索软件首次出现在2021年,作为CryptoJoker勒索软件的变种。该恶意软件通过钓鱼邮件和恶意链接传播,主要针对个人和小型企业用户。Plutocrypt使用了.NET框架开发,并依赖AES-256和RSA-4096的加密算法来加密受害者的文件。与Cr…...

IDEA启动提示Downloading pre-built shared indexes
Download pre-built shared indexes Reduce the indexing time and CPU load with pre-built JDK shared indexes 翻译: 下载预构建的共享索引 使用预构建的JDK共享索引减少索引时间和CPU负载. 使用预构建的JDK共享索引可以显著减少索引构建时间和CPU负载…...

[HCTF 2018]WarmUp 1--详细解析
打开靶机,进入界面: 信息搜集 当前界面没有任何有用信息。 想到查看页面源代码。右键–查看页面源代码 看到hint:<!--source.php--> 进入/source.php页面,看到页面源代码: <?phphighlight_file(__FILE_…...

软考教材重点内容 信息安全工程师 第1章 网络信息安全概述
第 1 章 网络信息安全概述 1.1.1 网络信息安全相关概念 狭义上的网络信息安全特指网络信息系统的各组成要素符合安全属性的要求,即机密性、完整性、可用性、抗抵赖性、可控性。 广义上的网络信息安全是涉及国家安全、城市安全、经济安全、社会安全、生产安全、人身安…...
TOSHIBA 74VHC00FT COMS汽车、工业企业的选择
74VHC00FT 是一种四路双输入 NAND 门,属于 CMOS 系列数字集成电路。它采用东芝先进的硅栅 C2MOS 技术设计,能够实现类似于双极性肖特基 TTL 逻辑电路的高速运行,同时保持 CMOS 器件的低功耗。这种独特的结合使其非常适合需要高性能和低功耗的…...

【Android】使用productFlavors构建多个变体
项目需求 在一个设备上安装两个一样的程序app 需求解决 我们知道每一个app都有一个包名的,如果一个app在Android设备上安装之后,再安装这个app的话会进行覆盖安装,因为他们两个的包名是一样的,默认是一个app。 但是我们现在需…...
ubuntu 22.04 防火墙 ufw
Ubuntu(22.04)云主机SSH安全加固 https://blog.csdn.net/qq_44846097/article/details/141098092 ubuntu22.04防火墙策略 https://blog.csdn.net/sunyuhua_keyboard/article/details/139493464 Ubuntu 22.04 防火墙设置和开放端口命令 https://blog.c…...

MySQL压缩版安装详细图解
1.下载 mysql压缩包版本和msi版的安装方法不一样,下面的是压缩包版本的安装详细图解: 总地址下载地址:MySQL :: Download MySQL Community Server MySQL :: Download MySQL Community Server (Archived Versions) 压缩版下载MySQL :: Dow…...

elementui中的新增弹窗在新增数据成功后再新增 发现数据无法清除解决方法
elementui中的新增弹窗在新增数据成功后再新增 发现数据无法清除解决方法 试过网上其他方法,发现表单清空数据还是有问题,索性用下面方法解决: // 给弹框里面添加 v-ifvisible测试无问题,暂时先这样解决,如果有其他方法&#x…...

软件开发项目管理:实现目标的实用指南
由于软件项目多数是复杂且难以预测的,对软件开发生命周期的深入了解、合适的框架以及强大的工作管理平台是必不可少的。项目管理系统在软件开发中通常以监督为首要任务,但优秀的项目计划、管理框架和软件工具可以使整个团队受益。 软件开发项目管理的主要…...
Jenkins面试整理-如何在 Jenkins 中进行并行构建?
在 Jenkins 中,并行构建 是通过并行执行多个任务来提高构建效率的常见方法。并行构建特别适用于需要执行多个独立步骤的工作流,如并行测试、构建不同平台上的软件或并行执行多个阶段。Jenkins 提供了两种方式来配置并行构建:Declarative Pipeline 和 Scripted Pipeline。下面…...
DPDK(F-Stack) 实现UDP通信
因刚开始学习DPDK,在学习过程中了解到需使用用户态协议栈,在网上找到F-Stack的相关介绍,但是缺乏DPDK的相关知识,导致使用F-Stack 时UDP数据无法收到 一文了解dpdk rte_ring无锁队列F-Stack实现UDP服务端、客户端,并进…...

基于ExtendSim的库存与订购实验
说明: 库存和订购实验室是一个单部件模拟模型,旨在测试从组件需求站点到组件分发站点的订购策略,以及 在组件分销现场的生产区域内。最佳解决方案允许为需求站点提供高服务级别,同时最大限度地降低总库存水平。 该模型演示了分层模…...
操作系统个人八股文总结
1.进程和线程的区别 进程和线程的定义 进程: 进程是一个运行中的程序实例,是资源分配的基本单位。每个进程都有自己的地址空间、数据、堆栈以及其他辅助数据。线程: 线程是进程中的一个执行单元,是CPU调度的基本单位。一个进程可…...

scala set训练
Set实训内容: 1.创建一个可变Set,用于存储图书馆中的书籍信息(假设书籍信息用字符串表示),初始化为包含几本你喜欢的书籍 2.添加两本新的书籍到图书馆集合中,使用操作符 3.删除一本图书馆集合中的书籍&…...
【d63】【Java】【力扣】141.训练计划III
思路 使用递归实现 出口 ,遇到null 每一层要做:把下层放进去,把本层放下去 代码 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { …...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...