java oracle 流复制_Oracle 流复制(Stream Replication)

Oracle Stream是一种基于日志挖掘的数据同步技术,用于数据库级别的数据共享和高可用性方案。与Data Guard不同,Stream不依赖触发器,而是通过Logminer还原日志为逻辑变更记录(LCR),实现双向、多级别数据同步。Stream复制包括捕获、传播和应用三个进程,涉及源数据库和目标数据库的队列管理。配置Stream涉及确定复制集、复制站点、LCR捕获方式和复制拓扑结构。在实际操作中,需关注参数设置、追加日志、表空间和用户创建、DBLink配置、队列和进程创建以及实例化复制数据库等步骤。
摘要由CSDN通过智能技术生成

Stream

是Oracle 的消息队列(也叫Oracle Advanced Queue)技术的一种扩展应用。 Oracle

的消息队列是通过发布/订阅的方式来解决事件管理。流复制(Stream

replication)只是基于它的一个数据共享技术,也可以被用作一个可灵活定制的高可用性方案。它可以实现两个数据库之间数据库级,schema级,Table级的数据同步,并且这种同步可以是双向的。

Oracle Stream也是通过数据冗余来提高可用性,这一点和Data Guard

类型。

Oracle 高级复制(Oracle advanced Replication)

和流复制(Stream Replication)

是从名称和功能上都相似的两种技术。但前者是基于触发器的,后者是基于日志挖掘(Logminer)技术。

1. Stream 的工作原理

Stream 是Oracle Advanced

Queue技术的一种扩展应用,这种技术最基本的原理就是收集事件,把时间保存在队列中,然后把这些事件发布给不同的订阅者。

从DBA的角度来说,就是把捕获Oracle数据库产生的Redo日志,然后把这些日志通过网络传播到多个数据库,其他数据库通过应用这些日志,达到复制变化的作用。

在Stream 环境下, 复制的起点数据库叫作Source Database,

复制的终点数据库叫作Target Database。 在这两个数据库上都要创建一个队列,其中的Source

Database上的是发送队列,而Target Database上的是接收队列。

数据库的所有操作都会被记录在日志中。 配好Stream环境后, 在Source

Database上会有一个捕获进程(Capture Process),

该进程利用Logminer技术从日志中提取DDL,DML语句,这些语句用一种特殊的格式表达,叫作逻辑变更记录(Logical

Change Record, LCR).

一个LCR对应一个原子的行变更,因此源数据库上的一个DML语句,可能对应若干个LCR记录。这些LCR会保存到Sourece

Database的本地发送队列中。然后传播进程(Propagation Process)把这些记录通过网络发送到Target

Database的接收队列。 在Target Database上会有一个应用进程(Apply

Process),这个进程从本地的接收队列中取出LCR记录,然后在本地应用,实现数据同步

2.  Data Guard 和Stream

区别

Date Guard有两种类型:physical standby 和 logical

standby。 这两中standby

都有3个功能模块:日志传送;日志接收,日志恢复。两种standby在前两个模块中是一样的,都是通过LGWR或者ARCn进程发送日志,通过RFS进程接受日志。区别在第三个模块:

Physical Standby 使用的是Media

Recovery技术直接在数据块级别进行恢复, 因此Physical Standby 能够做到两个数据库的完全同步,

没有数据类型限制。

Logical

Standby实际是通过Logminer技术,把日志中的记录还原成SQL语句,然后通过Apply Engine

执行这些语句实现数据同步, 因此Logical Standby不能保证数据的完全一致。 比如Logical Standby

不支持某些数据类型,这一点在选择Logical Standby时必须要考虑. Logical Standby

不支持的数据类型可以从DBA_LOGSTDBY_UNSUPPORTED是不里查看.

SQL>SELECT * FROM

DBA_LOGSTDBY_UNSUPPORTED;

Stream 使用的是Logical Standby 第三个模块,也就是在Source

Database一端,Capture 进程利用Logminer 技术把日志内容还原成LCR, 然后发送到Target

Database, 而在Target database 一端, 也是通过Apply Engine

执行这些LCR。因此Stream在使用上也有些限制条件。这些可以从视图ALL/DBA_STREAMS_NEWLY_SUPPORTED,

ALL/DBA_STREAMS_UNSUPPORTED

查看stream复制不支持的数据类型。

SQL>SELECT

table_name, reason FROM

ALL_STREAMS_NEWLY_SUPPORTED;

SQL>SELECT

table_name, reason FROM

DBA_STREAMS_NEWLY_SUPPORTED;

SQL>SELECT

table_name, reason FROM DBA_STREAMS_UNSUPPORTED;

SQL>SELECT

table_name, reason FROM ALL_STREAMS_UNSUPPORTED;

下面以图表的形式列举他们的区别:

Streams

Data Guard

主要目的是数据共享

主要目的是灾难恢复和高可用性

可以多方向同步

只能是单向,从Primary-->

Standby

数据粒度可以是数据库,Schema,Table三个级别

只有数据库级别

支持异种平台的同步(Heterogeneous

Platforms)

必须同种平台 (Homogeneous

Platforms)

参与复制的每个数据库可以读写

只有Primary可以读写,Standby

只读

支持Oracle 和非Oracle 数据库间的同步

只能是Oracle数据库间

3. 前期规划的几点:

1).

确定复制集:如是数据库级还是表级

2).

决定复制站点

3).

决定LCR是本地捕获还是下游捕获

本地捕获:

在源数据库进行,从联机日志和归档日志获得LCR

下游捕获:在目标数据库进行,从归档日志获得LCR.

本地捕获可以保护更多的数据,但是会占用源数据库的资源。

4).

决定复制拓扑结构:这时要决定复制数据库的用途,是只用于预防灾难,还是平时保持空闲,或允许用户使用。

4. Streams Replication 实例

4.1 准备工作:

DBA是源数据库, DBA2是目标数据库

4.1.1 源数据库和目标数据库必须是归档的

SQL> startup

mount;

SQL> alter database

archivelog;

SQL> alter database

open;

SQL> archive log

list

归档与非归档的切换请参考:

http://blog.csdn.net/tianlesoftware/archive/2009/10/18/4693470.aspx

或者

http://user.qzone.qq.com/251097186/blog/1236924069

4.1.2. 源数据库和目的数据库均需要设置的参数:

alter system set global_names=true scope =

both;

默认为false,  Database Link

使用的是数据库的global_name。

alter system set aq_tm_processes=2

scope=both;

以下参数都是10G的默认值, 检查下就可以了. 无需设置

如:Show parameter

job_queue_processes

alter system set job_queue_processes = 10

scope=both;

alter system set sga_target = 300m

scope=spfile;

alter system set open_links=4

scope=spfile;

alter system set statistics_level='TYPICAL'

scope=both;

10g 默认为Typical, 性能统计模式

alter system set

logmnr_max_persistent_sessions=1 scope=spfile;

10g 默认为1,持久的日志挖掘会话数。

alter system set "_job_queue_interval"=1

scope=spfile;

alter system set

aq_tm_processes=1;

alter system set streams_pool_size=200m

scope=both;

注意streams_pool_size一定要够大,因为如果启用了SGA_TARGET,ORACLE可能分配很少内存给stream导致大量信息被spill到磁盘导致查询DBA_APPLY,DBA_CAPTURE,DBA_PROPGATION全部状态ENABLED但就是没有数据被同步。

同时设置_job_queue_interval也是为了提高队列检查时间,防止apply出问题。

注意:与复制有关的2个参数:

如果等了足够长的时间发现数据没有复制过来,仔细检查了capture/propagation/apply各进程的状态都是正常的,并检查参数.

alter system set "_job_queue_interval"=1

scope=spfile;

并且将aq_tm_processes参数改为1(我原来这是为10)

alter system set

aq_tm_processes=1;

改完后重启,发现数据就可以去了。这个隐含参数只是控制对job队列的检查频率,默认5秒。

4.1.3 . 在源数据库上启用追加日志

可以基于Database级别或Table级别,启用追加日志(Supplemental

Log)。在建立根据Schema粒度进行复制的Oracle

Stream环境中,如果确认Schema下所有Table都有合理的主键(Primary

Key),则不再需要启用追加日志。

#启用Database 追加日志

alter database add supplemental log

data;

#启用Table追加日志

alter table add supplement log group

log_group_name(table_column_name) always;

4.1.4 .

源数据库和目的数据库创建相同表空间和用户并赋权

创建表空间:

CREATE TABLESPACE streams_tbs DATAFILE

'D:\ORACLE\ORADATA\DBA\streams_tbs.dbf' SIZE 100M REUSE AUTOEXTEND

ON MAXSIZE UNLIMITED;

CREATE TABLESPACE streams_tbs DATAFILE

'D:\ORACLE\ORADATA\DBA2\streams_tbs.dbf' SIZE 100M REUSE AUTOEXTEND

ON MAXSIZE UNLIMITED;

创建用户:

CREATE USER strmadmin IDENTIFIED BY strmadmin

DEFAULT TABLESPACE streams_tbs

QUOTA UNLIMITED ON

streams_tbs;

赋权:

GRANT DBA to strmadmin;

exec

DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE('strmadmin');

4.1.5

配置listener.ora和tnsnames.Ora

DBA2 =

(DESCRIPTION

=

(ADDRESS = (PROTOCOL = TCP)(HOST =

10.85.10.80)(PORT = 1521))

(CONNECT_DATA =

(SERVER =

DEDICATED)

(SERVICE_NAME =

DBA2.anqingren.org)

)

)

4.1.6 创建DBLink

先用strmadmin登陆,在创建dblink

4.1.6.1在源端建到目库的db link

SQL> conn

strmadmin/strmadmin;

已连接。

SQL> create database link DBA2

connect to strmadmin identified by strmadmin using

'dba2';

数据库链接已创建。

测试:

SQL> select * from

global_name@dba2;

GLOBAL_NAME

-------------------

DBA2.ANQINGREN.ORG

4.1.6.2 在目端建到源库的db link

SQL> conn

strmadmin/strmadmin;

已连接。

SQL> create database link dba

connect to strmadmin identified by strmadmin using

'dba';

数据库链接已创建。

4.2

用户级的复制(不支持sys和system用户)

4.2.1 最初的用户复制

分别在源库和目标数据库上创建测试用户

SQL>create user dave identified

by dave;

SQL>grant dba to

dave;

4.2.1 在源数据库上创建Source 队列

connect

strmadmin/strmadmin@dba;

BEGIN

DBMS_STREAMS_ADM.SET_UP_QUEUE(

queue_table => 'SOURCE_QUEUE_TABLE',

--队列表

queue_name

=> 'SOURCE_QUEUE',

--队列

queue_user

=> 'strmadmin');

--队列用户

END;

/

或者:

SQL> EXEC

DBMS_STREAMS_ADM.SET_UP_QUEUE();

PL/SQL procedure successfully

completed.

该命令会创建一个队列缺省名:streams_queue,队列表缺省是:STREAMS_QUEUE_TABLE

队列存储的object类型是anaydata

移除队列:

exec

dbms_streams_adm.remove_queue(

queue_name =>

'streams_queue',

cascade =>

true,

drop_unused_queue_table =>

true);.

可以用查询dba_queues,dba_queue_tables来检查:

SQL>  select

owner,queue_table,name from dba_queues where

owner='STRMADMIN';

OWNER  QUEUE_TABLE

NAME

----------------- -------------------------

------------------

STRMADMIN  SOURCES_QUEUE_TABLE  SOURCES_QUEUE

STRMADMIN  SOURCES_QUEUE_TABLE  AQ$_SOURCES_QUEUE_TABLE_E

SQL>select

owner,queue_table,object_type from dba_queue_tables where

owner='STRMADMIN';

OWNER  QUEUE_TABLE  OBJECT_TYPE

-------------- ---------------------

------------------

STRMADMIN  SOURCES_QUEUE_TABLE

SYS.ANYDATA

4.2.2 在目标数据库DBA2上创建接收队列

connect

strmadmin/strmadmin@dba2;

BEGIN

DBMS_STREAMS_ADM.SET_UP_QUEUE(

queue_table => 'TARGET_QUEUE_TABLE',

--队列表

queue_name

=> 'TARGET_QUEUE',

--队列

queue_user

=> 'strmadmin');

--队列用户

END;

/

可以用查询dba_queues,dba_queue_tables来检查:

SQL>  select

owner,queue_table,name from dba_queues where

owner='STRMADMIN';

OWNER  QUEUE_TABLE

NAME

------------------ ---------------------

----------------

STRMADMIN  TARGET_QUEUE_TABLE  TARGET_QUEUE

STRMADMIN  TARGET_QUEUE_TABLE  AQ$_TARGET_QUEUE_TABLE_E

4.2.3 在源数据库上创建capture 进程

SQL>conn

strmadmin/strmadmin@DBA;

SQL> BEGIN

DBMS_STREAMS_ADM.ADD_SCHEMA_RULES(

schema_name  => 'dave',  -- 用户名,如dave, 非sys或者system

streams_type

=> 'capture',

streams_name

=>

'capture_stream',

queue_name  =>

'strmadmin.SOURCE_QUEUE',

include_dml  =>

true,

include_ddl  => true,

source_database =>

'DBA',

include_tagged_lcr

=> false,

inclusion_rule  => true);

END;

/

PL/SQL procedure successfully

completed.

可以通过dba_capture查看:

SQL> select

CAPTURE_NAME,QUEUE_NAME,START_SCN,STATUS,CAPTURE_TYPE from

dba_capture;

CAPTURE_NAME  QUEUE_NAME  START_SCN  STATUS

CAPTURE_TY

-------------------------  ----------------------------

----------  --------------

----------------

CAPTURE_STREAM1

SOURCES_QUEUE  1294052  DISABLED  LOCAL

SQL> select * from

ALL_CAPTURE_PREPARED_SCHEMAS;

SCHEMA_NAME  TIMESTAMP

SUPPLEME  SUPPLEME SUPPLEME

SUPPLEME

--------------------  --------------  -------- --------  --------

--------

SYSTEM  20-10月-09  IMPLICIT  IMPLICIT

IMPLICIT  NO

4.2.4 在源数据库上创建传播进程

SQL>conn

strmadmin/strmadmin@DBA;

SQL> BEGIN

DBMS_STREAMS_ADM.ADD_SCHEMA_PROPAGATION_RULES(

schema_name

=>

'dave',

streams_name

=>

'source_to_target',

source_queue_name

=>

'strmadmin.SOURCE_QUEUE',

destination_queue_name

=>

'strmadmin.TARGET_QUEUE@DBA2', --此队列待创建

include_dml

=> true,

include_ddl

=> true,

source_database

=>

'DBA',

inclusion_rule

=> true,

queue_to_queue

=> true);

END;

/

PL/SQL procedure successfully

completed.

重新启动propagation process

--dbms_propagation_adm.start_propagation

(propagation_name)

--其中propagation_name可以从表all_propagation中取得

select * from

all_propagation;

SQL>

exec

dbms_propagation_adm.start_propagation('source_to_target');

exec

dbms_propagation_adm.stop_propagation('source_to_target');

PL/SQL procedure successfully

completed.

select * from

all_propagation;

可以通过dba_propagations查看结果:

SQL> select

PROPAGATION_NAME,SOURCE_QUEUE_NAME,DESTINATION_QUEUE_NAME,DESTINATION_DBLINK,STATUS

from dba_propagation;

PROPAGATION_NAME  SOURCE_QUEUE_NA DESTINATION_QUE DESTINATION_DBLINK

STATUS

------------------ ---------------

--------------- ------------------ --------

STREAM1_TO_STREAM2 SOURCES_QUEUE

TARGET_QUEUE  DBA2.ANQINGREN.ORG ENABLED

#修改propagation休眠时间为0,表示实时传播LCR。

begin

dbms_aqadm.alter_propagation_schedule(

queue_name =>

'SOURCE_QUEUE',

destination =>

'DBA2',

latency =>

0);

end;

/

4.2.5 在目标数据库DBA2上创建Apply进程

SQL> BEGIN

DBMS_STREAMS_ADM.ADD_SCHEMA_RULES(

schema_name  =>

'SYSTEM',

streams_type

=>

'apply',

streams_name

=>

'target_apply_stream',

queue_name  =>

'strmadmin.TARGET_QUEUE',

include_dml  => true,

include_ddl  => true,

include_tagged_lcr

=> false,

source_database

=> 'DBA',

inclusion_rule

=> true);

END;

/

可以通过:

dba_apply

v$streams_apply_reader

v$streams_apply_coordinator

v$streams_apply_server

查看状态

SQL> select

apply_name,queue_name,status from dba_apply;

APPLY_NAME  QUEUE_NAME

STATUS

------------------------------

------------------------------ --------

TARGET_APPLY_STREAM  TARGET_QUEUE

DISABLED

4.2.6

实例化复制数据库

4.2.6.1 用exp/imp 完成实例化

带数据完成源端exp和目端的import:

Exp USERID=SYSTEM/ADMIN@DBA OWNER=SYSTEM

FILE=D:\STRM.dmp LOG=STRM.log OBJECT_CONSISTENT=Y STATISTICS = NONE

imp USERID=SYSTEM/ADMIN@DBA2 FULL=Y

CONSTRAINTS=Y FILE=D:\STRM.dmp IGNORE=Y COMMIT=Y LOG=D:\import.log

STREAMS_INSTANTIATION=Y

或仅作实例化(不带数据):

exp USERID=SYSTEM/ADMIN@DBA OWNER=SYSTEM

FILE=D:\STRM.dmp LOG=D:\export.log OBJECT_CONSISTENT=Y STATISTICS =

NONE ROWS=NO

imp USERID=SYSTEM/ADMIN@DBA2 FULL=Y

CONSTRAINTS=Y FILE=D:\STRM.dmp COMMIT=Y LOG=D:\import.log

STREAMS_INSTANTIATION=Y IGNORE=Y

4.2.6.2 直接设置SCN的方式进行实例化:

---获取源库互置用户的SCN

connect strmadmin/strmadmin@DBA

set serveroutput on

DECLARE

iscn

NUMBER; -- Variable to hold instantiation SCN

value

BEGIN

iscn :=

DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER();

DBMS_OUTPUT.PUT_LINE ('Instantiation SCN is: ' ||

iscn);

END;

/

---设置为目标库互置用户的SCN

connect strmadmin/strmadmin@DBA2

BEGIN

DBMS_APPLY_ADM.SET_SCHEMA_INSTANTIATION_SCN(

source_schema_name => 'SYSTEM',

source_database_name =>

'DBA',

instantiation_scn =>

&iscn);

END;

/

4.2.7.

在目标数据库上启动Apply进程

connect

strmadmin/strmadmin@DBA2

SQL> BEGIN

DBMS_APPLY_ADM.SET_PARAMETER(apply_name

=> 'target_apply_stream',

parameter

=>

'disable_on_error', VALUE => 'n');

END;

/

SQL> BEGIN

DBMS_APPLY_ADM.START_APPLY(

apply_name =>

'target_apply_stream');

END;

/

#停止Apply进程

begin

dbms_apply_adm.stop_apply(

apply_name =>

'target_apply_stream');

end;

/

查看状态

SQL> select

apply_name,queue_name,status from dba_apply;

APPLY_NAME  QUEUE_NAME

STATUS

------------------------------

------------------------------ --------

TARGET_APPLY_STREAM  TARGET_QUEUE

ENABLED

4.2.8 在源数据库上启动capture

connect

strmadmin/strmadmin@DBA

SQL> BEGIN

DBMS_CAPTURE_ADM.START_CAPTURE(

capture_name =>

'capture_stream');

END;

/

#停止Capture进程

begin

dbms_capture_adm.stop_capture(

capture_name =>

'capture_stream');

end;

/

查看状态:

SQL> select capture_name,status

from dba_capture;

CAPTURE_NAME  STATUS

--------------- --------

CAPTURE_STREAM ENABLED

4.3  表级的复制

maintain_tts

表空间复制

maintain_schemas 用户复制

maintain_tables 表复制的

与dbms_streams_adm的maintain_global、maintain_tts、maintain_schemas等过程相比,maintain_tables过程使用则更灵活,可以为某些特殊的表拿出来单独配置,maintain_tables也象其它的过程一样,提供了一蓝子解决方案,如果要添加新的表到复制中,只需要再次执行maintain_tables过程即可。

4.3.1 在stream进行配置前,需要做些准备工作

A 源库与目标库初始化参数的设置

alter system set aq_tm_processes=1

scope=spfile;

alter system set job_queue_processes=2

scope=spfile;

alter system set global_names=true

scope=spfile;

alter system set streams_pool_size=20m

scope=spfile;

说明streams_pool_size在生产环境中最好>200m

B 源库与目标库tnsnames.ora配置

见4.1

C 源库与目标库复制管理员的创建

见4.1

D 在源库与目标库创建DBLINK

见4.1

E 源库与目标库必须处于归档模式

见4.1

F 源库与目标库必须创建directory

connect

strmadmin/strmadmin@DBA;

create directory DIR_DBA as

'D:\Stream\DBA';

connect

strmadmin/strmadmin@DBA2;

create directory DIR_DBA2 as

'D:\Stream\DBA2';

说明:在复制表空间时,创建directory需要指定该表空间所在的目录

G 创建测试用的表空间及表

CREATE TABLESPACE DAVE DATAFILE

'D:\ORACLE\ORADATA\DBA\DAVE.dbf' SIZE 100M;

create user tianle identified by tianle

default tablespace DAVE;

grant dba to tianle;

conn TIANLE/TIANLE

create table test(id int,name

varchar2(20));

create table test2(id int,name

varchar2(20));

insert into test

values(1,'dave');

insert into test

values(2,'bl');

不能使用默认的表空间.

4.3.2

在源库执行MAINTAIN_TTS过程

SQL>connect

strmadmin/strmadminpw@DBA;

declare

v_tables

dbms_utility.uncl_array;

begin

v_tables(1) := 'tianle.test;

v_tables(2) :=

'tianle.test2';

dbms_streams_adm.maintain_tables(

table_names =>

v_tables,

source_directory_object =>

null,

destination_directory_object =>

null,

source_database =>

'DBA',

destination_database =>

'DBA2',

perform_actions =>

true,

bi_directional =>

false,

include_ddl =>

true,

instantiation =>

dbms_streams_adm.instantiation_table_network);

end;

/

说明:在源库执行maintain_tables时,目标库几乎什么都不用做,stream环境已经配置好啦,

如果想复制其它的表,只用再执行maintain_tables过程即可

4.3.3 如果在执行2的过程时失败,需要清除脚本

--select script_id from

dba_recoverable_script;

--exec

dbms_streams_adm.RECOVER_OPERATION('&1','PURGE');

declare

v_script_id varchar2(32);

begin

select script_id into v_script_id from

dba_recoverable_script;

dbms_streams_adm.RECOVER_OPERATION(v_script_id,'PURGE');

exception

when no_data_found then

DBMS_OUTPUT.PUT_LINe('no data found')

;

when others then

4.5 全库级复制

以上主要为大家介绍了pre_instantiation_setup/post_instantiation_setup过程在配置全库复制的方法,以下介绍dbms_streams_adm的maintain_global过程如何配置stream全库复制方法,适用于10gR2及以后版本。

不支持sys/ system 用户的变更。

1.在stream进行配置前,需要做些准备工作

a 源库与目标库初始化参数的设置

alter system set aq_tm_processes=4

scope=spfile;

alter system set job_queue_processes=5

scope=spfile;

alter system set global_names=true

scope=spfile;

alter system set streams_pool_size=51m

scope=spfile;

说明streams_pool_size在生产环境中最好>200m

b 源库与目标库tnsnames.ora配置

见4.1

c 源库与目标库复制管理员的创建

见4.1

d 源库与目标库创建互连的DBLINK

见4.1

e 源库与目标库必须处于归档模式

见4.1

f 源库与目标库必须创建directory

create directory dir_DBA as

'D:\Stream\DBA';

create directory dir_DBA2 as

'D:\Stream\DBA2';

2.在源库执行MAINTAIN_GLOBAL过程

begin

dbms_streams_adm.maintain_global(

source_directory_object

=>'dir_DBA',

destination_directory_object

=>'dir_DBA2',

source_database=>'DBA',

destination_database

=>'DBA2',

perform_actions=>true,

include_ddl=>true,

instantiation=>DBMS_STREAMS_ADM.INSTANTIATION_FULL_NETWORK

);

end;

说明:在执行maintain_global时,源库与目标库必须创建directory,然后在源库执行,

目标库几乎什么都不用做,stream环境已经配置完毕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值