一篇文章让你上手Canal数据同步神技~

news2024/11/28 7:40:57

视频教程传送门:

Canal极简入门:一小时让你快速上手Canal数据同步神技~_哔哩哔哩_bilibiliCanal极简入门:一小时让你快速上手Canal数据同步神技~共计13条视频,包括:01.课前导学与前置知识点、02.Canal组件了解、03.MySQL主从复制原理等,UP主更多精彩视频,请关注UP账号。https://www.bilibili.com/video/BV1Uc411P7XN/?spm_id_from=333.337.search-card.all.click

一、前置知识点

1.1 Canal读音

流行的读法:Canal

1.2 前置知识点

  • MySQL 基本操作

  • Java 基础

  • SpringBoot

二、Canal介绍

2.1 历史背景

早期阿里巴巴在杭州和美国部署机房,存在跨机房同步的业务需求,最初的实现是基于业务触发的方式 ,不是是很方便, 2010 年,逐步使用数据库日志解析方式取代,这由此衍生出了大量的数据库增量订阅和消费操作。在这种背景下Canal就出来了。

2014年左右,天猫双十一首次引入,用于解决大型促销活动MySQL 数据库的高并发读写问题。后来,在阿里内部得到了广泛应用和推广,并于2017年正式开源。

Github:https://github.com/alibaba/canal

 

2.2 定义

Canal 组件是一个基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费,支持将增量数据投递到下游消费者(如 Kafka、RocketMQ 等)或者存储(如 Elasticsearch、HBase 等)的组件。

大白话: Canal 感知到MySQL数据变动,然后解析变动数据,将变动数据发送到MQ或者同步到其他数据库,等待进一步业务逻辑处理。

三、Canal的工作原理

3.1 MySQL主从复制原理

 

  • MySQL master 将数据变更写入二进制日志binary log,简称Binlog。

  • MySQL slave 将 master 的 binary log 拷贝到它的中继日志(relay log)

  • MySQL slave 重放 relay log 操作,将变更数据同步到最新。

3.2 MySQL Binlog日志

3.2.1 介绍

MySQL 的Binlog可以说 MySQL 最重要的日志,它记录了所有的 DDL 和 DML语句,以事件形式记录。

MySQL默认情况下是不开启Binlog,因为记录Binlog日志需要消耗时间,官方给出的数据是有1%的性能损耗。

具体开不开启,开发中需要根据实际情况做取舍。

一般来说,在下面两场景下会开启Binlog日志:

  • MySQL 主从集群部署时,需要将在 Master 端开启 Binlog,方便将数据同步到Slaves中。

  • 数据恢复了,通过使用 MySQL Binlog 工具来使恢复数据。

3.2.1 Binlog的分类

MySQL Binlog 的格式有三种,分别是 STATEMENT,MIXED,ROW。在配置文件中可以选择配

置 binlog_format= statement|mixed|row

分类介绍优点缺点
STATEMENT语句级别,记录每一次执行写操作的语句,相对于ROW模式节省了空间,但是可能产生数据不一致如update tt set create_date=now(),由于执行时间不同产生饿得数据就不同节省空间可能造成数据不一致
ROW行级,记录每次操作后每行记录的变化。假如一个update的sql执行结果是1万行statement只存一条,如果是row的话会把这个1万行的结果存这。持数据的绝对一致性。因为不管sql是什么,引用了什么函数,他只记录执行后的效果占用较大空间
MIXED是对statement的升级,如当函数中包含 UUID() 时,包含 AUTO_INCREMENT 字段的表被更新时,执行 INSERT DELAYED 语句时,用 UDF 时,会按照 ROW的方式进行处理节省空间,同时兼顾了一定的一致性还有些极个别情况依旧会造成不一致,另外statement和mixed对于需要对binlog的监控的情况都不方便

综合上面对比,Canal 想做监控分析,选择 row 格式比较合适。  

3.3 Canal 工作原理

  • Canal 将自己伪装为 MySQL slave(从库) ,向 MySQL master (主库)发送dump 协议

  • MySQL master(主库) 收到 dump 请求,开始推送 binary log 给 slave (即 canal )

  • Canal 接收并解析 Binlog 日志,得到变更的数据,执行后续逻辑

 

四、Canal运用场景

4.1 数据同步

Canal 可以帮助用户进行多种数据同步操作,如实时同步 MySQL 数据到 Elasticsearch、Redis 等数据存储介质中。

4.2 数据库实时监控

Canal 可以实时监控 MySQL 的更新操作,对于敏感数据的修改可以及时通知相关人员。

4.3 数据分析和挖掘

Canal 可以将 MySQL 增量数据投递到 Kafka 等消息队列中,为数据分析和挖掘提供数据来源。

 

4.4 数据库备份

Canal 可以将 MySQL 主库上的数据增量日志复制到备库上,实现数据库备份。

 

4.5 数据集成

Canal 可以将多个 MySQL 数据库中的数据进行集成,为数据处理提供更加高效可靠的解决方案。

4.6 数据库迁移

Canal 可以协助完成 MySQL 数据库的版本升级及数据迁移任务。

 

五、MySQL准备

5.1 创建数据库

新建库:canal-demo

 

5.2 创建表

用户表

CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

5.3 修改配置文件开启Binlog支持

修改mysql的配置文件, 一名名字为: my.ini

server-id=1
log-bin=C:/ProgramData/MySQL/MySQL Server 8.0/binlogs/mysql-bin.log
binlog_format=row
binlog-do-db=canal-demo

server-id:mysql 实例id,集群时用于区分实例

lob-bin:binlog日志文件名称

binlog_format:binlog日志数据保存格式

binlog-do-db:指定开启binlog日志数据库。

注意:一般根据情况进行指定需要同步的数据库,如果不配置则表示所有数据库均开启 Binlog。

5.4 校验Binlog生效

重启MySQL服务,查看Binlog日志

方式1:

show  VARIABLES like 'log_bin'

 

方式2:

进入指定目录:

insert into user(name, age) values('dafei', 18);
insert into user(name, age) values('dafei', 18);
insert into user(name, age) values('dafei', 18);

 

 

六、Canal安装与配置

6.1 下载

地址:Releases · alibaba/canal · GitHub

解压即可。

6.2 配置

6.2.1修改canal.properties的配置

canal.port = 11111
# tcp, kafka, rocketMQ, rabbitMQ, pulsarMQ
canal.serverMode = tcp

canal.destinations = example

canal.port:默认端口 11111

canal.serverMode:服务模式,tcp 表示输入客户端,xxMQ输出到各类消息中间件

canal.destinations:canal能可以收集多个MySQL数据库数据,每个MySQL数据库都有独立的配置文件控制。具体配置规则: conf/目录下,使用文件夹放置,文件夹名代表一个MySQL实例。canal.destinations用于配置需要监控数据的数据库。如果是多个,使用,隔开

6.2.2 修改MySQL实例配置文件instance.properties

config/目录下

canal.instance.mysql.slaveId=20

# position info
canal.instance.master.address=127.0.0.1:3306

# username/password
canal.instance.dbUsername=root
canal.instance.dbPassword=admin

canal.instance.mysql.slaveId:使用canal 从阶段id

canal.instance.master.address:数据库ip端口

canal.instance.dbUsername:连接mysql账号

canal.instance.dbPassword:连接mysql密码

6.3 启动

双击启动

 

七、Canal编程

7.1 Helloworld

1>创建项目:canal-hello

2>导入相关依赖

<dependency>
    <groupId>com.alibaba.otter</groupId>
    <artifactId>canal.client</artifactId>
    <version>1.1.0</version>
</dependency>

3>编写测试代码

package com.langfeiyes.hello;

import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CanalDemo {

    public static void main(String[] args) throws InvalidProtocolBufferException {
        //1.获取 canal 连接对象
        CanalConnector canalConnector = CanalConnectors.newSingleConnector(new InetSocketAddress("localhost", 11111), "example", "", "");
        while (true) {
            //2.获取连接
            canalConnector.connect();
            //3.指定要监控的数据库
            canalConnector.subscribe("canal-demo.*");
            //4.获取 Message
            Message message = canalConnector.get(100);
            List<CanalEntry.Entry> entries = message.getEntries();
            if (entries.size() <= 0) {
                System.out.println("没有数据,休息一会");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                for (CanalEntry.Entry entry : entries) {
                    // 获取表名
                    String tableName = entry.getHeader().getTableName();
                    //  Entry 类型
                    CanalEntry.EntryType entryType = entry.getEntryType();
                    //  判断 entryType 是否为 ROWDATA
                    if (CanalEntry.EntryType.ROWDATA.equals(entryType)) {
                        //  序列化数据
                        ByteString storeValue = entry.getStoreValue();
                        //  反序列化
                        CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(storeValue);
                        // 获取事件类型
                        CanalEntry.EventType eventType = rowChange.getEventType();
                        // 获取具体的数据
                        List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
                        // 遍历并打印数据
                        for (CanalEntry.RowData rowData : rowDatasList) {
                            List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
                            Map<String, Object> bMap = new HashMap<>();
                            for (CanalEntry.Column column : beforeColumnsList) {
                                bMap.put(column.getName(), column.getValue());
                            }
                            Map<String, Object> afMap = new HashMap<>();
                            List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
                            for (CanalEntry.Column column : afterColumnsList) {
                                afMap.put(column.getName(), column.getValue());
                            }
                            System.out.println("表名:" + tableName + ",操作类型:" + eventType);
                            System.out.println("改前:" + bMap );
                            System.out.println("改后:" + afMap );
                        }
                    }
                }
            }
        }
    }
}

4>测试

对canal-demo 库中user表进行DML操作,观察打印值

Canal API 体系分析

 

7.2 SpringBoot集成

1>创建项目:canal-sb-demo

2>导入相关依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-parent</artifactId>
    <version>2.7.11</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>top.javatool</groupId>
        <artifactId>canal-spring-boot-starter</artifactId>
        <version>1.2.6-RELEASE</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.12</version>
    </dependency>
    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.21.4</version>
    </dependency>
</dependencies>

 3>配置文件

canal:
  server: 127.0.0.1:11111 #canal 默认端口11111
  destination: example
spring:
  application:
    name: canal-sb-demo
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/canal-demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
    username: root
    password: admin

4>实体对象

package com.langfeiyes.sb.domain;

public class User {
    private Long id;
    private String name;
    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}

5>监控处理类

package com.langfeiyes.sb.handler;

import com.langfeiyes.sb.domain.User;
import org.springframework.stereotype.Component;
import top.javatool.canal.client.annotation.CanalTable;
import top.javatool.canal.client.handler.EntryHandler;

@Component
@CanalTable(value = "user")
public class UserHandler implements EntryHandler<User> {
 
    @Override
    public void insert(User user) {
        System.err.println("添加:" + user);
    }
 
    @Override
    public void update(User before, User after) {
        System.err.println("改前:" + before);
        System.err.println("改后:" + after);

    }
    @Override
    public void delete(User user) {
        System.err.println("删除:" + user);
    }
}

6>启动类

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

7>测试

  • 先启动canal服务器

  • 再启动项目

  • 修改user表

  • 观察结果

八、同类型技术

类型1:基于日志解析的数据同步组件

这类组件主要是通过解析数据库的Binlog(MySQL)或者Redo Log(Oracle)等日志文件,获取到数据库的增删改操作,并将这些操作记录下来。然后,这些操作记录可以被传输到另一个数据库中,以达到数据同步的目的。此类组件的代表产品包括阿里开源的Canal、腾讯云的DBSync等。

类型2:基于ETL的数据同步组件

ETL即Extract-Transform-Load,指的是从源系统抽取数据、对数据进行转换处理、最终加载到目标系统中。这类组件通常需要编写复杂的数据转换规则和数据映射关系,适用于数据结构变动频繁、数据量较大、数据来源较多的场景。代表产品包括阿里云的DataWorksInformatica PowerCenter等。

类型3:基于CDC的数据同步组件

CDC(Change Data Capture)即变更数据捕获,它是一种数据同步技术,能够在实时或准实时地捕获数据库中的数据变更,并将其传输到另一个数据库中。CDC技术基于数据库的事务日志或重做日志实现,能够实现低延迟、高性能的数据同步。CDC组件的代表产品包括Oracle GoldenGate、IBM Infosphere Data Replication等。

类型4:基于消息队列的数据同步组件

这类组件通常将数据库中发生的变更操作抽象成一种数据结构,并通过消息队列将其发布到其他系统中进行处理,实现数据的异步传输和解耦。代表产品包括Apache Kafka、RabbitMQ等。

九、Canal常见面试题

问:Canal是什么?有哪些特性?

答:Canal是阿里巴巴开源的一款基于Netty实现的分布式、高性能、可靠的消息队列,在实时数据同步和数据分发场景下有着广泛的应用。Canal具有以下特性:支持MySQL、Oracle等数据库的日志解析和订阅;支持多种数据输出方式,如Kafka、RocketMQ、ActiveMQ等;支持支持数据过滤和格式转换;拥有低延迟和高可靠性等优秀的性能指标。

问:Canal的工作原理是什么?

答:Canal主要通过解析数据库的binlog日志来获取到数据库的增、删、改操作,然后将这些变更事件发送给下游的消费者。Canal核心组件包括Client和Server两部分,Client负责连接数据库,并启动日志解析工作,将解析出来的数据发送给Server;Server则负责接收Client发送的数据,并进行数据过滤和分发。Canal还支持多种数据输出器,如Kafka、RocketMQ、ActiveMQ等,可以将解析出来的数据发送到不同的消息队列中,以便进行进一步的处理和分析。

问:Canal的优缺点是什么?

答:Canal的优点主要包括:高性能、分布式、可靠性好、支持数据过滤和转换、跨数据库类型(如MySQL、Oracle等)等。缺点包括:使用难度较大、对数据库的日志产生一定的影响、不支持数据的回溯(即无法获取历史数据)等。

问:Canal在业务中有哪些应用场景?

答:Canal主要用于实时数据同步和数据分发场景,常见的应用场景包括:数据备份与灾备、增量数据抽取和同步、数据实时分析、在线数据迁移等。特别是在互联网大数据场景下,Canal已经成为了各种数据处理任务的重要工具之一。

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

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

相关文章

光纤收发器可以连接光模块吗?

随着科技的进步发展&#xff0c;城市信息化速度的加快&#xff0c;光通信产品在数据中心和安防监控等场景中的运用越来越广泛&#xff0c;而这之间的连接则需要光模块和光纤收发器来实现。很多用户对光模块和光纤收发器的使用有些疑虑&#xff0c;两者该如何连接&#xff1f;又…

2023年5月实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先&#xff0c;来看下效果图 在线体验地址&#xff1a;https://geojson.hxkj.vip&#xff0c;并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

第7章链接:重定位、可执行目标文件、加载可执行目标文件

文章目录 7.7 重定位7.7.1 重定位表目7.7.2 重定位符号引用重定位PC相关的引用重定位绝对引用 7.8 可执行目标文件7.9 加载可执行目标文件 7.7 重定位 一旦链接器完成了符号解析这一步&#xff0c;它就把代码中的每个符号引用和确定的一个符号定义&#xff08;也就是&#xff…

自学成材的黑客很多,但还是得掌握方法,给你黑客入门与进阶建议

建议一&#xff1a; 黑客七个等级&#xff08;仅供参考&#xff09; 黑客&#xff0c;对很多人来说充满诱惑力。很多人可以发现这门领域如同任何一门领域&#xff0c;越深入越敬畏&#xff0c;知识如海洋&#xff0c;黑客也存在一些等级&#xff0c;参考知道创宇 CEO ic&#…

如何把图片无损放大?教你图片怎么无损放大

随着数字图像技术的不断发展&#xff0c;图片无损放大成为了许多人关注的问题。当我们需要将小图片放大到更大的尺寸时&#xff0c;使用传统的放大方法可能会导致图片失真、模糊等质量问题。那么如何在保持高清晰度和精度的同时进行无损放大&#xff0c;一直是一个备受关注的课…

数字化时代,如何从战略设计到架构来打造智慧银行?

导语 | 随着人工智能、大数据、云计算等技术向纵深发展&#xff0c;数字化转型已成为银行发展的“必答题”。调整战略规划和架构重组、加大信息科技投入、推进科技人才队伍建设、持续推出数字化产品……近年来&#xff0c;深化数字化转型&#xff0c;以科技赋能金融服务已成为不…

【C++初阶】第十三篇:模板进阶(非类型模板参数、模板的特化以及模板的分离编译)

文章目录 一、非类型模板参数二、模板的特化2.1 概念2.2 函数模板特化2.3 类模板特化2.3.1 全特化2.3.2 偏特化/半特化 三、模板的分离编译3.1 什么是分离编译3.2 模板的分离编译3.3 解决方法 四、模板总结 一、非类型模板参数 模板参数类型可分为&#xff1a;类型形参和非类型…

通达信SCTR强势股选股公式,根据六个技术指标打分

SCTR指标(StockCharts Technical Rank)的思路来源于著名技术分析师约翰墨菲&#xff0c;该指标根据长、中、短三个周期的六个关键技术指标对股票进行打分&#xff0c;根据得分对一组股票进行排名&#xff0c;从而可以识别出强势股。 与其他技术指标一样&#xff0c;SCTR的设计…

中国社科院与美国杜兰大学能源管理硕士项目是你职场通关的密码吗

职场是一场没有硝烟的战争&#xff0c;想要在职场取得取胜&#xff0c;就要拥有超能力。从职场小白晋升到管理层一路走来诸多不易&#xff0c;想要坐稳或升得更高&#xff0c;要不断提升自己能力&#xff0c;要不间断地学习。社科院与美国杜兰大学能源管理硕士项目是你通关的密…

navicat连接oracle报错 ORA-28547

报错 原因 Navicat自带的oci.dll并不支持oracle11g 具体操作 1. 先用idea连接oracle&#xff0c;查看oracle版本 select * from v$version; 2. 去官网下载 Instant Client 地址&#xff1a; Oracle Instant Client Downloads 下载 选择对应的版本&#xff08;下载时&#x…

未注册老域名扫描软件-免费未注册老域名挖掘

未注册老域名挖掘教程 在SEO优化中&#xff0c;老域名的价值不言而喻&#xff0c;它们的搜索引擎权重、离线广告效果等都比新域名更高。然而&#xff0c;如何挖掘出高质量的老域名并进行注册并非易事。今天&#xff0c;我们将介绍一款名为“147SEO老域名挖掘软件”的工具&…

【SpringBoot】二:自动配置

文章目录 1.自动配置类2. Import3. AutoConfigurationImportSelector4. AutoConfiguration 1.自动配置类 Spring Boot的自动装配机制会试图根据你所添加的依赖来自动配置你的Spring应用程序。 例如&#xff0c;如果你添加了Mysql依赖&#xff0c;而且你没有手动配置任何DataS…

从今天起,不再为 API 烦恼 !

做技术管理的童鞋&#xff0c;往往会陷入这样一种困境&#xff1a;疲于奔命&#xff0c;到处救火填坑&#xff0c;沟通推进&#xff0c;却挤不出时间思考对团队和项目来说真正重要的事情。 你有没有经历过这样的场景&#xff1a; 1. 下属老是改了接口但不维护文档&#xff0c;屡…

初探高并发—ExecutorCompletionService

初探高并发—ExecutorCompletionService 为什么要引入高并发 众所周知&#xff0c;程序中的代码是从下往下顺序执行的&#xff0c;当我们需要在一个方法中同时执行多个耗时的任务时所消耗时间就会大于等于这些任务消耗的累加时间。那么有没有一种办法可以让这些耗时的任务同时…

微信小程序入门04-后端脚手架搭建

我们上一篇已经介绍了权限系统的库表搭建&#xff0c;光有表还是不够的&#xff0c;我们还需要有一个后台系统和数据库进行交互。搭建后台的时候既需要选择使用什么语言&#xff0c;也需要选择框架。 框架分为前端框架和后端框架。在第一篇微信开发者工具搭建的时候我们其实前…

面试官:什么是防抖和节流?如何实现?应用场景?

防抖 与 节流 大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 前言 防抖和节流作为很多大厂的经典面试题&#xff0c;问倒了许多小伙伴&a…

【Python-ESL】python-esl安装

pip install python-esl 时会报错&#xff1a; “error: command ‘swig’ failed with exit status 1” 报错原因是 因为 swig 软件未正确安装&#xff0c;当然对swig的版本也是有要求的&#xff0c;目前测试以下版本没有问题&#xff1a; swig3.0.63 python-ESL1.4.18(app-…

域名年龄查询工具-域名历史查询工具

批量域名历史查询工具 在近几年的网络营销中&#xff0c;老域名已经成为获取网站排名和SEO优化的重要途径。而对于购买这些老域名&#xff0c;了解域名的过往经历&#xff0c;可以帮助我们更好地评估域名的价值&#xff0c;并避免购买不良的域名。因此&#xff0c;今天我们将向…

微信小程序入门03-搭建权限系统,建库建表

我们准备零基础搭建一个小程序&#xff0c;小程序分为两部分&#xff0c;一个是用户访问的程序&#xff0c;可以是小程序也可以是H5。另外一个就是管理员使用的管理后台&#xff0c;后台第一个要实现的就是搭建权限系统。为了搭建权限系统&#xff0c;我们先需要梳理概念 1 RB…

Oracle自增序列探秘:一篇文章教你读懂

目录 1&#xff1a;什么是Oracle 自增长序列 2 &#xff1a;创建数据-->实现自增长序列 2.1 创建序列 2.2 使用序列 3 &#xff1a;查询数据-->实现自增长序列 1&#xff1a;什么是Oracle 自增长序列 Oracle自增长序列是一种生成唯一数字的方法&#xff0c;可以用于创…