首页 > 数据库 > 国内数据库 > OceanBase 物理备份恢复
为什么
OceanBase 提供了多副本同步机制,还需要进行备份?
多副本和备份恢复的关注点:
SSTable)。Clog(Redo Log)。OBDumper 导出数据库的逻辑结构和数据,不涉及底层物理文件。
OBCP 实验考试时候,会在 OCP 配置一个 NFS Server,我们需要手动挂载到三个
OBServer 服务器的相同目录。
#1、启动 nfs-server $ systemctl start nfs-server #2、在其他三台 OBServer 服务器再次测试,均能访问 $ showmount -e 192.168.11.200 Export list for 192.168.11.200: /data/nfs_server * #3、 三台 OBServer 创建目录并挂载,无需更改属组 $ mkdir -p /data/ob_backup mount -t nfs4 -o rw,nfsvers=4.1,sync,lookupcache=positive,hard,timeo=600,wsize=1048576,rsize=1048576,namlen=255 192.168.11.200:/data/nfs_server /data/ob_backup #4、 三台 OBServer检查 $ df -h Filesystem Size Used Avail Use% Mounted on 192.168.11.200:/data/nfs_server 99G 12G 83G 12% /data/ob_backup #8、随后开始白屏操作,新建租户级备份策略,执行全量备份
/data/log1 目录中。Paxos 协议将日志同步发送给对应的
Follower 节点,多数派节点确认写入成功后事务方可提交。MemTable)已经通过转储(Mini/Minor Freeze)或合并(Major Compaction)持久化到了磁盘的基线/增量数据文件(SSTable)中。Clog 必须已经被成功归档到外部存储介质(如 OSS/NFS)中。Clog 所涵盖的事务必须已经全部提交或回滚,不存在活动的长事务占用。 日志归档是指日志数据的
自动持续归档功能,
OBServer 节点会自动且持续地
将事务日志归档到指定的备份路径。
Redo Log 记录。OceanBase 是多租户数据库,每个租户可以独立决定是否开启日志归档功能,各租户之间的日志归档相互独立、互不影响。OceanBase 和传统
Oracle 数据库归档与备份路径的机制对比Oracle 开启归档后,在线日志(
Online Redo Log)写满触发切换,
ARCn 后台进程将日志复制到
本地归档路径(如本地磁盘或 shared disk 的
ARCHIVELOG 目录)。RMAN 备份是一个
主动发起的批处理任务。执行
RMAN 脚本时,才将数据文件、控制文件以及存储在本地的归档日志
二次拷贝到最终的备份路径(如 tape等)。Clog
实时、持续(Stream)地直接写入远端备份路径(如 NFS、阿里云 OSS 等对象存储)。SSTable 宏块)独立定期进行;而日志归档则在后台不断地向远端备份介质追加,
不需要在本地占用专门的“归档日志存放目录”进行中转。数据备份是指 OceanBase 数据库 定期地将存储在磁盘上的数据文件(SSTable)复制并传输到指定的外部存储介质的过程。
OceanBase 支持以下两种数据备份方式:
租户级独立配置:
OceanBase 作为多租户数据库,每个租户可以独立配置并开启数据备份功能,租户间互不影响。Follower 副本上执行。 优点是:Leader 的磁盘与 CPU 资源,保障生产读写无延迟。OBServer 节点的工作负载。Paxos 协议,
Follower 上的
SSTable 与
Leader 完全一致,保证备份数据的正确性。 在开启日志归档前,必须先配置归档路径(
LOG_ARCHIVE_DEST)和相关策略。
ALTER SYSTEM SET LOG_ARCHIVE_DEST='LOCATION=archive_path [BINDING=archive_mode] [PIECE_SWITCH_INTERVAL=piece_switch_interval]' [TENANT = tenant_name];
虽然可以通过 ALTER SYSTEM 设置
LOG_ARCHIVE_DEST 参数,但它不是一个配置项。因此,不能通过
SHOW PARAMETERS like xx 查询。 参数详细说明:
LOCATION (必选):指定归档目的地(路径和文件目录),支持 NFS、对象存储介质。BINDING (可选):配置归档与业务的优先模式,默认为
Optional 模式。Optional(业务优先)
:优先保证业务正常进行。如果归档跟不上,Clog 回收时不会等待
归档完成,可能会发生归档断流(缺日志) ,后续可能无法恢复到断流点之后。Mandatory(归档优先)
:优先保证数据安全性。Clog 回收必须等待
日志成功归档。若归档介质故障或卡住,会导致本地 Clog 无法回收,进而触发磁盘空间满**并影响业务写入。PIECE_SWITCH_INTERVAL (可选):配置 piece(片段)的切换周期,取值范围为
[1d, 7d],默认为
1d。
OceanBase 按照
Piece 来组织管理归档数据,一个
Piece 代表某个租户在连续一段时间内完备日志的集合。TENANT (可选):在
SYS 系统租户中执行时,必须指定用户租户名;若直接在普通
用户租户下执行,则无需指定。# /data/obbackup 必须是共享目录,archive 文件夹不用手动创建 ALTER SYSTEM SET LOG_ARCHIVE_DEST='LOCATION=file:///data/obbackup/archive' TENANT = obmysql; # 执行完会创建如下文件夹和文件 [root@oceanbase2 archive]# pwd /data/obbackup/archive [root@oceanbase2 archive]# ll total 4 drwx------ 2 admin admin 53 Sep 7 09:30 check_file -rw------- 1 admin admin 142 Sep 7 09:30 format.obbak drwx------ 7 admin admin 149 Sep 7 09:31 piece_d1001r1p1 drwx------ 2 admin admin 57 Sep 7 09:31 pieces drwx------ 2 admin admin 39 Sep 7 09:31 rounds [root@oceanbase1 archive]# cd piece_d1001r1p1/ [root@oceanbase1 piece_d1001r1p1]# ll total 4 drwx------ 2 admin admin 86 Sep 7 09:33 checkpoint drwx------ 4 admin admin 36 Sep 7 09:31 logstream_1 drwx------ 3 admin admin 17 Sep 7 09:31 logstream_1001 drwx------ 3 admin admin 17 Sep 7 09:31 logstream_1002 drwx------ 3 admin admin 17 Sep 7 09:31 logstream_1003 -rw------- 1 admin admin 125 Sep 7 09:31 tenant_archive_piece_infos.obarc
/archive/ 目录:
format.obbak :
归档格式化标记文件。记录了当前归档路径的格式版本、创建时间、集群/租户元数据等信息。OceanBase 在使用该目录作为归档目的地时会生成此文件,用以校验归档目录的合法性与兼容性。piece_d1001r1p1/ :
具体的归档分片目录(Piece 目录)。命名规则一般为
piece_d<dest_id>r<round_id>p<piece_id>:d1001:归档目的地 ID(Destination ID)。r1:归档轮次(Round 1),表示第 1 次开启归档。如果关闭归档后重新开启,轮次会递增。p1:分片编号(Piece 1),归档数据会按时间或大小切割成多个 Piece 依次递增(如 p1, p2, p3...)。pieces/ : 记录 Piece 生命周期和状态历史的目录,存放与 Piece 切换相关的历史元数据文件。rounds/ :记录归档轮次(Round)状态与历史元数据的目录,用于追踪每次开启/关闭归档的生命周期。check_file/ :归档自检与完整性校验目录,OceanBase 后台任务会通过该目录下的校验文件确认归档数据的完整性。
piece_d1001r1p1/ 内部目录结构:
checkpoint/ :
归档检查点目录。记录当前 Piece 内各个日志流(Logstream)的归档进度(Archive SCN),确保恢复时能够精确知道日志的连续性和边界。logstream_1/ 及
logstream_100x/ :
日志流数据目录。OceanBase 4.x 采用多日志流架构:logstream_1:系统日志流,存放系统租户/租户级系统表(如元数据、事务状态表)的 Redo 日志。logstream_1001,
1002,
1003...:用户数据日志流,对应表空间/分区的用户数据写入 Redo 日志。日志流内部包含分段切片的
.pal 或
.arc 日志文件。tenant_archive_piece_infos.obarc :
Piece 碎片元数据文件。记录了当前租户下所有 Piece(归档分片)的状态、起始时间/SCN、结束时间/SCN 等全局信息,供恢复(Restore)时快速定位需要拉取哪些分片。-- 系统租户查看所有租户的日志归档路径 SELECT * FROM oceanbase.CDB_OB_ARCHIVE_DEST; +-----------+---------+-----------------------+-------------------------------+ | TENANT_ID | DEST_NO | NAME | VALUE | +-----------+---------+-----------------------+-------------------------------+ | 1002 | 0 | binding | OPTIONAL | | 1002 | 0 | dest_id | 1001 | | 1002 | 0 | path | file:///data/obbackup/archive | | 1002 | 0 | piece_switch_interval | 1d | | 1002 | 0 | state | ENABLE | +-----------+---------+-----------------------+-------------------------------+ -- 当前租户查看本租户的日志归档路径 SELECT * FROM DBA_OB_ARCHIVE_DEST; +---------+-----------------------+-------------------------------+ | DEST_NO | NAME | VALUE | +---------+-----------------------+-------------------------------+ | 0 | binding | OPTIONAL | | 0 | dest_id | 1001 | | 0 | path | file:///data/obbackup/archive | | 0 | piece_switch_interval | 1d | | 0 | state | ENABLE | +---------+-----------------------+-------------------------------+
配置好目的地后,执行 SQL 开启归档:
-- 开启归档 ALTER SYSTEM ARCHIVELOG [TENANT = tenant_name]; -- 关闭归档 ALTER SYSTEM NOARCHIVELOG [TENANT = tenant_name]; -- 当前租户查看本租户归档进度 SELECT ROUND_ID, DEST_ID, PATH, STATUS, START_SCN_DISPLAY, CHECKPOINT_SCN_DISPLAY FROM DBA_OB_ARCHIVELOG; +----------+---------+-------------------------------+--------+----------------------------+----------------------------+ | ROUND_ID | DEST_ID | PATH | STATUS | START_SCN_DISPLAY | CHECKPOINT_SCN_DISPLAY | +----------+---------+-------------------------------+--------+----------------------------+----------------------------+ | 1 | 1001 | file:///data/obbackup/archive | DOING | 2026-09-07 09:31:14.422245 | 2026-09-07 09:47:14.747743 | +----------+---------+-------------------------------+--------+----------------------------+----------------------------+ -- sys 租户查看指定租户 SELECT TENANT_ID, STATUS, PATH, COMMENT FROM oceanbase.CDB_OB_ARCHIVELOG WHERE TENANT_ID = 1002; +-----------+--------+-------------------------------+---------+ | TENANT_ID | STATUS | PATH | COMMENT | +-----------+--------+-------------------------------+---------+ | 1002 | DOING | file:///data/obbackup/archive | | +-----------+--------+-------------------------------+---------+
核心字段解读:
ROUND_ID :归档轮次,开启归档为 1,重新开启会递增。STATUS :归档状态,常见如
DOING(正在归档)、
STOP(停止)。START_SCN_DISPLAY :本次归档的起点时间位点。CHECKPOINT_SCN_DISPLAY :最新归档成功的位点(在此之前的日志都已经安全入库)。OceanBase V4 可以为日志归档和数据备份设置不同的目的地(或目录)。
ALTER SYSTEM SET DATA_BACKUP_DEST='data_backup_path' [TENANT = tenant_name]; -- sys 租户执行 ALTER SYSTEM SET DATA_BACKUP_DEST='file:///data/obbackup/data' TENANT = obmysql; -- 查看日志归档、数据备份与密钥文件的全部存储信息 SELECT * FROM DBA_OB_BACKUP_STORAGE_INFO; +-----------+-------------------------------+----------+---------+-------------+---------------+-----------+-----------------------------------------+----------------------------+ | TENANT_ID | PATH | ENDPOINT | DEST_ID | DEST_TYPE | AUTHORIZATION | EXTENSION | CHECK_FILE_NAME | LAST_CHECK_TIMESTAMP | +-----------+-------------------------------+----------+---------+-------------+---------------+-----------+-----------------------------------------+----------------------------+ | 1002 | file:///data/obbackup/archive | | 1001 | archive_log | | | 1002_connect_file_20260907T093030.obbak | 2026-09-07 09:31:04.396272 | | 1002 | file:///data/obbackup/data | | 1002 | backup_data | | | 1002_connect_file_20260907T095248.obbak | 2026-09-07 09:52:48.905751 | +-----------+-------------------------------+----------+---------+-------------+---------------+-----------+-----------------------------------------+----------------------------+ -- 查看数据备份配置 SELECT * FROM DBA_OB_BACKUP_PARAMETER; +------------------+----------------------------+ | NAME | VALUE | +------------------+----------------------------+ | data_backup_dest | file:///data/obbackup/data | +------------------+----------------------------+ -- sys 租户下查看所有租户 SELECT * FROM oceanbase.CDB_OB_BACKUP_PARAMETER; +-----------+------------------+----------------------------+ | TENANT_ID | NAME | VALUE | +-----------+------------------+----------------------------+ | 1002 | data_backup_dest | file:///data/obbackup/data | +-----------+------------------+----------------------------+
系统租户使用
CDB_OB 视图查看所有租户的信息,用户租户使用
DBA_OB 视图查看本租户的信息。
数据备份可以是全量备份,也可以是增量备份,执行增量备份前至少要有一份全量备份。
-- 发起全量备份
ALTER SYSTEM BACKUP {DATABASE | TENANT = tenant_name} [PLUS ARCHIVELOG];
-- 发起增量备份
ALTER SYSTEM BACKUP INCREMENTAL {DATABASE | TENANT = tenant_name};
参数说明:
DATABASE
:在
SYS 租户下执行时,表示对所有租户 发起备份;在普通用户租户下执行时,仅对
当前租户 生效。PLUS ARCHIVELOG (可选):在发起全量备份的同时,将当期的归档日志一并打包拷贝到数据备份目录下,形成一个自我包含、具备独立恢复能力的数据集(无需额外依赖外部归档目录)。执行备份并查看备份任务进度与历史:
-- 在 obmysql 租户下面执行备份 ALTER SYSTEM BACKUP DATABASE; -- 查看当前正在执行的数据备份任务 SELECT JOB_ID, -- 备份任务ID BACKUP_SET_ID, -- 备份集ID INITIATOR_TENANT_ID, -- 租户ID BACKUP_TYPE, -- 备份类型 (FULL/INC) STATUS, -- 当前状态 (DOING/COMPLETED/FAILED) START_TIMESTAMP, -- 开始时间 END_TIMESTAMP, -- 结束时间 PATH -- 备份存储路径 FROM DBA_OB_BACKUP_JOBS; +--------+---------------+---------------------+-------------+--------+----------------------------+---------------+----------------------------+ | JOB_ID | BACKUP_SET_ID | INITIATOR_TENANT_ID | BACKUP_TYPE | STATUS | START_TIMESTAMP | END_TIMESTAMP | PATH | +--------+---------------+---------------------+-------------+--------+----------------------------+---------------+----------------------------+ | 1 | 1 | 1002 | FULL | DOING | 2026-09-07 09:55:46.415275 | NULL | file:///data/obbackup/data | +--------+---------------+---------------------+-------------+--------+----------------------------+---------------+----------------------------+ -- 查看备份历史摘要 SELECT TENANT_ID, ROUND_ID, STATUS, START_SCN, CHECKPOINT_SCN, COMMENT FROM oceanbase.CDB_OB_ARCHIVELOG_SUMMARY WHERE TENANT_ID = 1002; +-----------+----------+--------+---------------------+---------------------+---------+ | TENANT_ID | ROUND_ID | STATUS | START_SCN | CHECKPOINT_SCN | COMMENT | +-----------+----------+--------+---------------------+---------------------+---------+ | 1002 | 1 | DOING | 1788744674422245711 | 1788746595096081692 | | +-----------+----------+--------+---------------------+---------------------+---------+ -- 查看已经完成或失败的历史备份任务记录 SELECT JOB_ID, BACKUP_TYPE, PLUS_ARCHIVELOG, START_TIMESTAMP, END_TIMESTAMP, STATUS, RESULT FROM DBA_OB_BACKUP_JOB_HISTORY; -- sys 租户下查看备份进度 SELECT * FROM oceanbase.CDB_OB_BACKUP_JOBS; -- sys 租户查看备份历史 SELECT JOB_ID, -- 备份任务ID BACKUP_SET_ID, -- 备份集ID INITIATOR_TENANT_ID, -- 租户ID BACKUP_TYPE, -- 备份类型 (FULL/INC) STATUS, -- 当前状态 (DOING/COMPLETED/FAILED) START_TIMESTAMP, -- 开始时间 END_TIMESTAMP, -- 结束时间 PATH -- 备份存储路径 FROM oceanbase.CDB_OB_BACKUP_JOB_HISTORY; +--------+---------------+---------------------+-------------+-----------+----------------------------+----------------------------+----------------------------+ | JOB_ID | BACKUP_SET_ID | INITIATOR_TENANT_ID | BACKUP_TYPE | STATUS | START_TIMESTAMP | END_TIMESTAMP | PATH | +--------+---------------+---------------------+-------------+-----------+----------------------------+----------------------------+----------------------------+ | 1 | 1 | 1002 | FULL | COMPLETED | 2026-09-07 09:55:46.415275 | 2026-09-07 09:57:42.262472 | file:///data/obbackup/data | +--------+---------------+---------------------+-------------+-----------+----------------------------+----------------------------+----------------------------+ -- 查看备份文件 [root@oceanbase1 data]# cd backup_set_1_full/ [root@oceanbase1 backup_set_1_full]# pwd /data/obbackup/data/backup_set_1_full [root@oceanbase1 backup_set_1_full]# ll 4.0K backup_set_1_full_20260907T095548_20260907T095742.obbak 204K infos 39M logstream_1 184K logstream_1001 136K logstream_1002 136K logstream_1003 4.0K single_backup_set_info.obbak 4.0K tenant_backup_set_infos.obbak
视图速查汇总:
| 目的 | 系统租户视图 (SYS) | 用户租户视图 |
|---|---|---|
| 日志归档目的地 |
CDB_OB_ARCHIVE_DEST |
DBA_OB_ARCHIVE_DEST |
| 日志归档状态/进度 |
CDB_OB_ARCHIVE_LOG |
DBA_OB_ARCHIVE_LOG |
| 数据备份目的地 |
CDB_OB_BACKUP_PARAMETER |
DBA_OB_BACKUP_PARAMETER |
| 运行中的备份任务 |
CDB_OB_BACKUP_JOBS |
DBA_OB_BACKUP_JOBS |
| 历史备份任务 |
CDB_OB_BACKUP_JOB_HISTORY |
DBA_OB_BACKUP_JOB_HISTOR |
物理恢复本质上是基于物理备份(数据备份与归档日志)在
OceanBase 中重建租户或表的过程。恢复出来的租户可以位于原集群,也可以跨集群恢复到新的目标集群。
truncate table
闪回查询、回收站都无法恢复,只能使用备份恢复。Oracle 数据库的恢复是
原地覆盖,用备份文件覆盖当前数据库里的数据文件;
OceanBase 的恢复是
异位生成,重新创建一个全新的目标租户,原始租户
完全不受影响,可正常提供读写服务。 物理恢复租户首先要新建目标租户,新建租户遵循三部曲(创建资源规格、创建资源池、创建租户关联资源池),然后将物理备份的数据恢复到目标租户中,最后通过重做
clog 日志来恢复数据到指定的一致点。
在
SYS 系统租户下创建目标租户所需的资源:
CREATE RESOURCE UNIT u1 MAX_CPU 1, MEMORY_SIZE = '2G';
CREATE RESOURCE POOL p1 unit = 'u1', unit_num = 1, zone_list = ('zone1','zone2','zone3');
ALTER SYSTEM RESTORE dest_tenant_name FROM uri [ UNTIL {TIME='timestamp' | SCN=scn} ] WITH 'restore_option';
-- 系统租户执行恢复,指定备份路径和日志归档路径,并指定资源池
ALTER SYSTEM RESTORE mysql FROM 'file:///data/obbackup/data,file:///data/obbackup/archive' WITH 'pool_list=p1&primary_zone=zone1';
使用
DBA_OB_RESTORE_PROGRESS 查看正在执行的恢复任务,使用
DBA_OB_RESTORE_HISTORY 查看已经完成的恢复任务。
-- 系统租户下查看所有租户恢复状态 SELECT * FROM oceanbase.CDB_OB_RESTORE_PROGRESS; SELECT JOB_ID, RESTORE_TENANT_NAME, -- 恢复生成的新租户名 BACKUP_TENANT_NAME, -- 原始备份租户名 STATUS, -- 当前恢复阶段 (如 CREATE_TENANT, RESTORE_USER_DATA) RESTORE_SCN_DISPLAY, -- 恢复目标时间点 RESTORE_PROGRESS, -- 恢复进度百分比 START_TIMESTAMP -- 任务开始时间 FROM oceanbase.CDB_OB_RESTORE_PROGRESS; +--------+---------------------+--------------------+----------------------------+----------------------------+------------------+----------------------------+ | JOB_ID | RESTORE_TENANT_NAME | BACKUP_TENANT_NAME | STATUS | RESTORE_SCN_DISPLAY | RESTORE_PROGRESS | START_TIMESTAMP | +--------+---------------------+--------------------+----------------------------+----------------------------+------------------+----------------------------+ | 2 | mysql | obmysql | WAIT_TENANT_RESTORE_FINISH | 2026-09-07 10:35:15.536058 | NULL | 2026-09-07 10:36:13.943372 | | 2 | mysql | obmysql | RESTORING | 2026-09-07 10:35:15.536058 | 99.83 | 2026-09-07 10:36:13.943372 | +--------+---------------------+--------------------+----------------------------+----------------------------+------------------+----------------------------+ --在 sys 租户下确认租户状态 SELECT TENANT_ID, TENANT_NAME, STATUS, -- 状态:TENANT_STATUS_NORMAL 表示正常 IN_RECYCLEBIN, PRIMARY_ZONE, CREATE_TIME FROM oceanbase.DBA_OB_TENANTS WHERE TENANT_NAME = 'mysql'; +-----------+-------------+--------+---------------+-------------------+----------------------------+ | TENANT_ID | TENANT_NAME | STATUS | IN_RECYCLEBIN | PRIMARY_ZONE | CREATE_TIME | +-----------+-------------+--------+---------------+-------------------+----------------------------+ | 1004 | mysql | NORMAL | NO | zone1;zone2,zone3 | 2026-09-07 10:36:21.915478 | +-----------+-------------+--------+---------------+-------------------+----------------------------+ -- 用户租户查看当前正在执行的恢复任务 SELECT * FROM oceanbase.DBA_OB_RESTORE_PROGRESS; -- 用户租户查看已完成的恢复历史记录 SELECT * FROM oceanbase.DBA_OB_RESTORE_HISTORY;
点击 OCP 租户页面,此时可看到恢复出来的
mysql 租户是备租户:

obclient -h192.168.182.22 -P2881 -uroot@mysql -p'OBexampas123%^&' -c -A -Dlab4spm obclient [lab4spm]> insert into tb1 values(1,1,'a','a'); ERROR 4688 (HY000): standby tenant is read only
连接备租户发现插入数据报错,因为备租户是只读状态。准确来讲: 备份恢复过程就是搭建了一个备租户,把备租户应用日志到指定时间点。后续可选择作为灾备库持续日志同步(主备租户),也可选择激活成主租户(备份恢复)。
刚恢复完成的租户默认处于 备租户 状态( 只读),需要根据业务场景执行激活或日志追赶操作。
如果该恢复租户用来作为灾备库,可以开启日志持续同步:
-- 持续回放源租户的日志
ALTER SYSTEM RECOVER STANDBY [TENANT = tenant_name] UNTIL { TIME='timestamp' | SCN=scn_no | UNLIMITED };
如果恢复目的是数据救急或搭建新独立环境,需将其提升为主租户:
-- 将备租户激活为主租户(使其具备读写能力) ALTER SYSTEM ACTIVATE STANDBY [TENANT = tenant_name]; obclient [oceanbase]> ALTER SYSTEM ACTIVATE STANDBY TENANT=mysql; Query OK, 0 rows affected (2.408 sec)
OCP 页面已经显示为: 主租户

激活成为主租户后,便可插入数据了。

如果将 低版本集群备份出的数据恢复到了 高版本集群中,转为主租户后必须执行租户升级流程:
-- 升级租户元数据与内部表结构 ALTER SYSTEM RUN UPGRADE JOB "UPGRADE_ALL" TENANT = tenant_name;
注意:只有当恢复出来的租户已经转换为
主租户(Active Master) 后,才能执行
RUN UPGRADE JOB 升级操作。
最后看一下 OCP 页面,刚刚执行的备份任务和日志同步:


这里是《实战派K8S&DB》,全网同名。如果本文对你有所帮助,欢迎点赞、推荐和转发,也欢迎关注后续文章,一起考证、一起学习 OceanBase 分布式数据库。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31444449/viewspace-3181768/ ,如需转载,请注明出处,否则将追究法律责任。