修復由於主庫NOLOGGING操作引起的備庫ORA-01578和ORA-26040錯誤
- 2019 年 10 月 11 日
- 筆記
修復由於主庫NOLOGGING操作引起的備庫ORA-01578和ORA-26040錯誤
(一)NOLOGGING操作引起的壞塊(ORA-01578和ORA-26040)簡介
如果只是錯誤ORA-01578,而沒有伴隨ORA-26040,那麼這個壞塊是由其它的原因引起的壞塊,可以嘗試使用RMAN的BMR(Block Media Recovery)修復。
如果數據段(表段、索引段)被定義為NOLOGGING屬性,那麼當NOLOGGING加APPEND、UNRECOVERABLE操作修改該數據段或者使用數據泵(DATAPUMP)impdp參數DISABLE_ARCHIVE_LOGGING:Y時,聯機重做日誌只會記錄很少的日誌信息。如果這些聯機重做日誌或歸檔日誌被用來恢複數據文件,那麼Oracle會將對應的數據塊標誌為無效(Soft Corrupt),而且下一次訪問這些數據塊時,會報ORA-01578和ORA-26040錯誤。
例如:
SQL> select * from test_nologging;
ORA-01578: ORACLE data block corrupted (file # 11, block # 84)
ORA-01110: data file 4: '/oradata/users.dbf'
ORA-26040: Data block was loaded using the NOLOGGING option
數據字典視圖DBA_TABLES、DBA_INDEXES、DBA_LOBS、DBA_TAB_PARTITIONS、DBA_LOB_PARTITIONS、DBA_TAB_SUBPARTITIONS中的LOGGING列記錄了NOLOGGING屬性。若LOGGING='NO'則表示NOLOGGING。
數據泵DATAPUMP的impdp參數DISABLE_ARCHIVE_LOGGING:Y在執行導入時會禁止LOGGING定義,而產生NOLOGGING操作。如果相應的datafile被restored和recovered,那麼接下來的涉及到目標表的查詢會報錯ORA-1578和ORA-26040。如果數據庫是FORCE LOGGING模式,那麼DISABLE_ARCHIVE_LOGGING選項不會關閉LOGGING。
impdp使用參數「DISABLE_ARCHIVE_LOGGING:Y」的一個例子:
impdp scott/tiger directory=DATA_PUMP_DIR dumpfile=dp transform=disable_archive_logging:y
NOLOGGING導致的壞塊不會導致RMAN備份失敗。一般來說soft corrupt block不會導致RMAN備份失敗,不需要設置MAXCORRUPT。數據庫備份中就會含有soft corrupt block,如果使用這些備份恢複數據,那麼恢復的數據也含有soft corrupt block。
除ORA-26040錯誤之外,當還有一些其他通用信息出現時,block dump可能會被產生。如果數據塊的block dump內有byte 0xff信息或者屬於某個段,ORA-1578和ORA-26040會因為介質恢復了NOLOGGING的部分導致了corruption而出現。
(二)利用RMAN、DBV檢測NOLOGGING導致的壞塊
DBV在檢測壞塊時,如果RDBMS版本小於10.2.0.4,那麼DBV打印錯誤DBV-200,如果RDBMS版本大於或等於10.2.0.4,那麼DBV打印錯誤DBV-201:
DBV-00200: Block, dba 46137428, already marked corrupted DBV-00201: Block, DBA 46137428, marked corrupt for invalid redo application
RMAN的VALIDATE命令可以用來檢測NOLOGGING數據塊,檢查結果記錄在視圖V$DATABASE_BLOCK_CORRUPTION(小於12c的版本)和V$NONLOGGED_BLOCK(12c及其以上)。
下面的例子中檢查出DATAFILE 4有933壞塊,查詢V$DATABASE_BLOCK_CORRUPTION或者V$NONLOGGED_BLOCK。
RMAN> VALIDATE DATABASE; ... ..... File Status Marked Corrupt Empty Blocks Blocks Examined High SCN ---- ------ -------------- ------------ --------------- ---------- 4 OK 933 1 6401 2275124 File Name: /oracle/dbs/users.dbf
RMAN在檢測壞塊時,如果RDBMS版本小於10.2.0.5和11.1.0.7,RMAN打印如下錯誤:
10.2.0.4 and lower, 11.1.0.6, 11.1.0.7: RMAN validate reports it in v$database_block_corruption with CORRUPTION_TYPE=LOGICAL
如果RDBMS版本大於或等於10.2.0.5和11.2.0.1,RMAN報告,查看視圖v$database_block_corruption中CORRUPTION_TYPE=NOLOGGING的記錄。
10.2.0.5 and 11.2.0.1+:
RMAN validate reports it in v$database_block_corruption with CORRUPTION_TYPE=NOLOGGING
在12c及以後版本中,RMAN validate的結果不在視圖v$database_block_corruption中,而是在視圖v$nonlogged_block。從12.2 版本開始,可以使用新的命令:「validate .. nonlogged block」去驗證nologging的block。
在以下的例子中,數據文件5和6有nologged的block:
RMAN> validate database nonlogged block; Starting validate at ... using target database control file instead of recovery catalog allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID=133 device type=DISK channel ORA_DISK_1: starting validation of datafile channel ORA_DISK_1: validation complete, elapsed time: 00:00:35 List of Datafiles ================= File Status Nonlogged Blocks Blocks Examined Blocks Skipped ---- ------ ---------------- --------------- -------------- 1 OK 0 106363 0 2 OK 0 78919 0 3 OK 0 96639 0 4 OK 0 4991 0 5 OK 400 2559 0 6 OK 569 2559 0 Details of nonlogged blocks can be queried from v$nonlogged_block view
在告警日誌中會更新以下信息:
Started Nonlogged Block Replacement recovery(validate) on file 5 (ospid 26351 rcvid 10616970560844821494)
Finished Nonlogged Block Replacement recovery(validate) on file 5. 400 blocks found
Started Nonlogged Block Replacement recovery(validate) on file 6 (ospid 26351 rcvid 10616970560844821494)
Finished Nonlogged Block Replacement recovery(validate) on file 6. 569 blocks found
(三)監控NOLOGGING操作
若執行了NOLOGGING操作,並且之後在沒有備份的情況下,RMAN命令「REPORT UNRECOVERABLE」可以查詢出被影響的datafile。
RMAN> report unrecoverable;
using target database control file instead of recovery catalog
Report of files that need backup due to unrecoverable operations
File Type of Backup Required Name
—- ———————– ———————————–
4 full or incremental /oracle/dbs/users.dbf
當初始化參數db_unrecoverable_scn_tracking設置為true(默認值,該參數在10g中是不可用的),那麼V$DATAFILE中以下列會被更新;
SYS@lhr121> select UNRECOVERABLE_CHANGE# ,
2 UNRECOVERABLE_TIME ,
3 FIRST_NONLOGGED_SCN ,
4 FIRST_NONLOGGED_TIME from v$datafile where file#=6;
UNRECOVERABLE_CHANGE# UNRECOVERABLE_TIME FIRST_NONLOGGED_SCN FIRST_NONLOGGED_TIM
——————— ——————- ——————- ——————-
2878238 2018-04-10 10:53:47 2878238 2018-04-10 10:53:47
在11.2.0.4 或12.1.0.2+版本中,設置event 16490的情況下,物理備庫的MRP進程會檢查出NOLOGGING變化,並記錄在alert log。
ORA-16490 "logging invalidated blocks on standby due to invalidation redo"
"INVD_BLKS: Invalidating (file <file number>, bno <block number>)"
"fname: 'Datafile name'. rdba: …"
(四)識別數據塊什麼時候被標誌為NOLOGGING
識別數據塊什麼時候被標誌為NOLOGGING,可以將trace文件中數據塊SCN或者v$database_block_coruption視圖中CORRUPTION_CHANGE#值轉換為時間:
① 使用trace文件中數據塊SCN,例如:
Start dump data blocks tsn: 60 file#: 4 minblk 84 maxblk 84
buffer tsn: 3 rdba: 0x02c00054 (11/84)
scn: 0x0771.4fa24eb5 seq: 0xff flg: 0x04 tail: 0x4eb500ff
提取SCN值0x0771.4fa24eb5,刪除'.',然後轉換0x07714fa24eb到十進制511453045995。
② 使用v$database_block_coruption視圖中CORRUPTION_CHANGE#值
如果運行RMAN validate命令後,v$database_block_coruption視圖中corruption_type='NOLOGGING' (10.2.0.5 和 11.2.0.1+),那麼CORRUPTION_CHANGE#列的值就是十進制的SCN值。可以使用下面的方法獲得SCN Timestamp時間:
select scn_to_timestamp(&&decimal_scn) from dual;
如果運行RMAN validate:
select file#, block#, scn_to_timestamp(CORRUPTION_CHANGE#)
from v$database_block_corruption
where CORRUPTION_TYPE='NOLOGGING';
在12c中:
select file#, block#, scn_to_timestamp(NONLOGGED_START_CHANGE#) from v$nonlogged_block;
如果查詢gv$archived_log 或 gv$log_history遇到錯誤ORA-08181:
alter session set nls_date_format = 'DD-MON-YY HH24:MI:SS';
select first_time, next_time
from gv$archived_log
where &decimal_scn between first_change# and next_change#;
或
select first_time
from gv$log_history
where &decimal_scn between first_change# and next_change#;
如果運行RMAN validate:
alter session set nls_date_format = 'DD-MON-YY HH24:MI:SS';
select file#, block#, first_time, next_time
from v$archived_log, v$database_block_corruption
where CORRUPTION_CHANGE# between first_change# and next_change#
and CORRUPTION_TYPE='NOLOGGING';
或
select file#,block#,first_time
from v$log_history, v$database_block_corruption
where CORRUPTION_CHANGE# between first_change# and next_change#
and CORRUPTION_TYPE='NOLOGGING';
12c:
alter session set nls_date_format = 'DD-MON-YY HH24:MI:SS';
select file#, block#, first_time, next_time
from v$nonlogged_block, v$archived_log
where NONLOGGED_START_CHANGE# between first_change# and next_change#;
或
select file#, block#, first_time
from v$nonlogged_block, v$log_history
where NONLOGGED_START_CHANGE# between first_change# and next_change#;
(五)SYSAUX表空間、AWR、EM等出現NOARCHIVELOG和NOLOGGING問題
如果數據庫版本是11.1.0.6 或 11.1.0.7 或 11.2.0.1,對NOLOGGING對象執行過DIRECT PATH操作,並且後續執行了RECOVER DATABASE命令,即使數據庫FORCE LOGGING是打開的情況下,會出現ORA-1578和ORA-26040錯誤。這種問題經常發生在SYSAUX表空間中的AWR或EM對象。請參考Note 1071869.1。注意數據庫當前版本可能已經大於11.1 或者11.2.0.1但是問題可能是在升級之前產生的。這個約束在11.2.0.2以上版本中取消,這個問題在10g不會發生。
RDBMS版本變化:
RDBMS版本 |
變化 |
---|---|
10.2.0.4+ |
DBverify報告NOLOGGING block錯誤信息 "DBV-00201: Block, DBA <rdba>, marked corrupt for invalid redo application" |
10.2.0.5, 10.2.0.1+ |
RMAN validate命令檢查NOLOGGING block,在v$database_block_coruption視圖中記錄corruption_type='NOLOGGING' |
11g+ |
引入db_unrecoverable_scn_tracking參數 |
11.1.0.6 or 11.1.0.7 or 11.2.0.1 |
NOARCHIVELOG模式數據庫,對NOLOGGING對象執行了DIRECT PATH操作,並且以後手動恢複數據庫,即使打開了FORCE LOGGING,也會報ORA-1578 和 ORA-26040。這個約束在11.2.0.2以上版本取消,這個問題在10g不會發生。 |
12c |
RMAN validate的結果不在視圖v$database_block_corruption中,而是在視圖v$nonlogged_block |
12.2 |
以下RMAN命令被引入:RMAN> validate [database / datafile] nonlogged block;RMAN> recover [database / datafile] nonlogged block; -> 對於 Standby 數據庫 |
(六)解決方法
NOLOGGING操作引起的壞塊是不能修復的,比如「Media Recovery」或「RMAN blockrecover」都無法修復這種壞塊。可行的方法是在NOLOGGING操作之後立刻備份對應的數據文件。
如果錯誤是執行RMAN DUPLICATE 或 RESTORE之後產生的,那麼在源庫打開FORCE LOGGING,然後再重新運行RMAN DUPLICATE 或 RESTORE。
alter database force logging;
如果錯誤出現在物理STANDBY數據庫,那麼可以從主庫恢復被影響的數據文件(只有當主庫沒有這個問題的情況下)。參考文檔Doc ID 958181.1。在Oracle 12c中可以使用RMAN選項RECOVER NONLOGGED BLOCK with DATAFILE、TABLESPACE、DATABASE。例如:
RMAN> RECOVER DATABASE NONLOGGED BLOCK;
為了避免這個問題發生,在主庫強制生產日誌:
alter database force logging;
如果同一個datafile的數據塊在主庫出現nologging壞塊,但是備庫沒有,可以通過手動跳過(dbms_repair)壞塊或者設置event 10231。主庫出現nologging壞塊可能是由於主庫執行過備份恢復或者之前是備庫,執行了switchover。
如果NOLOGGING數據塊位於空閑數據塊(dba_free_space視圖可以查詢到),那麼DBVerify檢查會發現這個問題,報錯DBV-00201或者在v$database_block_corruption視圖中顯示。對於這種情況,可以等待到這個數據塊被重用時會自動格式化或者手動強制格式化。
如果是索引,那麼可以重新創建(drop/create)索引。如果是表,那麼可以使用存儲過程DBMS_REPAIR.SKIP_CORRUPT_BLOCKS跳過壞塊,然後考慮是否重建表。
在刪除有壞塊的段之後,這個壞塊就處於空閑狀態,後續可以被分配給其他對象或段,當這個壞塊被分配給其它對象或段時,這個數據塊被重新格式化。如果v$database_block_corruption視圖中還是顯示為壞塊,那麼可以手動運行rman validate來清除視圖中的信息。
如果是LOB,那麼請參考Note 293515.1。
眾所周知 , DG 數據同步是基於日誌流的 , 這也是為什麼在配置 DG 階段需要 將主庫設置為 FORCE LOGGING 的原因 。但是 , 這也會帶來很多問題 , SQL 執行效率 慢 ,例如:當我們使用數據泵進行遷移時我們希望最少停機時間完成,這時候我們就可能會考慮到以最小日誌導入的方式以加快導入速度,然後重新同步備庫。
在一些場景中,我們會去使用 nologging 操作去節省大量數據插入的時間,而這種操作所帶來的問題就是,如果該庫在有備庫的情況下,因為主庫的 nologging 插入操作不會生成 redo ,所以不會在備庫上傳輸和應用,這會導致備庫的數據出現問題。
在一個具有主備關係的主庫上將 force_logging 設置為 nologging 模式,隨後創建一張表,設置為 nologging 模式:
SQL> alter database no force logging;
SQL> create table DEMO tablespace users pctfree 99 as select rownum n from xmltable('1 to 100');
SQL> alter table DEMO nologging;
之後使用 /* +append*/ 插入數據並提交
SQL> insert /*+ append */ into DEMO select rownum n from xmltable('1 to 1000');
SQL> commit
這時候在備庫對該表進行查詢會看到如下報錯信息
SQL>select count(1) from demo;
select count(1) from demo
*
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 4, block # 819)
ORA-01110: data file 4: '/data/data1/ORCL2/datafile/o1_mf_users_3ft1e9qb_.dbf'
ORA-26040: Data block was loaded using the NOLOGGING option
1.1 11g
在 Oracle 11g 中 ,如果遇到這樣的問題,可以通過在備庫恢復有問題的數據文件來解決問題 。 而要修復這個問題,需要將包含缺少的數據的數據文件從主庫複製到物理備庫。
1 、查詢主庫
SQL> SELECT NAME, UNRECOVERABLE_CHANGE# FROM V$DATAFILE;
NAME UNRECOVERABLE_CHANGE#
——————————————– ———————
+DATADG/orcl/datafile/system.270.972381717 0
+DATADG/orcl/datafile/sysaux.265.972381717 0
+DATADG/orcl/datafile/undotbs1.261.972381717 0
+DATADG/orcl/datafile/users.259.972381717 6252054
+DATADG/orcl/datafile/example.264.972381807 0
+DATADG/orcl/datafile/undotbs2.258.972381927 0
+DATADG/orcl/datafile/example.266.972400297 0
+DATADG/orcl/datafile/ax.268.973612569 0
2 、查詢備庫
sys@ORCL>SELECT NAME, UNRECOVERABLE_CHANGE# FROM V$DATAFILE;
NAME UNRECOVERABLE_CHANGE#
——————————————— ———————
/data/data1/ORCL2/datafile/o1_mf_system_3dt1e9op_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_sysaux_3ct1e9nb_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_undotbs1_3gt1e9qq_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_users_3ft1e9qb_.dbf 5383754
/data/data1/ORCL2/datafile/o1_mf_example_3et1e9ps_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_undotbs2_3ht1e9r1_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_example_3at1e9nb_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_ax_3bt1e9nb_.dbf 0
3 、比較主數據庫和備用數據庫的查詢結果
在兩個查詢結果中比較 UNRECOVERABLE_CHANGE# 列的值。如果主庫中 UNRECOVERABLE_CHANGE #列的值大於備庫中的同一列,則需要將這些數據文件在備庫恢復。
將主庫對應的數據文件拷貝至備庫 :
SQL> alter tablespace users begin backup ;
SQL> exit
ASMCMD>cp +DATADG/orcl/datafile/users.259.972381717 /tmp
$ scp /tmp/users.259.972381717 10.10.60.123:/data/data1/ORCL2/datafile/
SQL> alter tablespace users end backup ;
備庫將舊的數據文件 RENAME 至新的數據文件 :
SQL> startup mount force
SQL> alter database recover managed standby database cancel;
SQL> alter system set standby_file_management=manual; # 在備庫執行 rename 操作時,需要此參數為manual
SQL> alter database rename file '/data/data1/ORCL2/datafile/o1_mf_users_3ft1e9qb_.dbf' to '/data/data1/ORCL2/datafile/users.259.972381717';
SQL> alter system set standby_file_management=auto;
SQL> alter database recover managed standby database using current logfile disconnect from session;
之後就可以在備庫查詢到實例表 DEMO
SQL> select count(1) from demo;
COUNT(1)
———-
1 1 00
1.2 12.1
對於這種情況,在 12.1 版本中, RMAN 提供了一種便捷的方式讓我們不需要在主庫上進行數據文件的備份傳輸而可以在備庫使用 restore database (or datafile ) from service 去從主庫進行恢復。
當然, Oracle 的 RMAN 是足夠聰明的:如果數據文件是正常的狀態, RMAN 可以根據它們的數據文件頭進行跳躍恢復。如果,由於 nologging 操作導致某些塊被標記為損壞的,那麼這部分數據文件就是需要恢復的,然後怎麼辦?在恢復命令中有 FORCE 選項。但我們可能並不需要它。因為有些時候數據文件是同步的,實時日誌應用進程還是在運行的。這個時候,為了恢復,我們需要停止應用。
一旦我們停止了應用,那麼就不需要執行 RESOTORE DATABASE FORCE 操作,因為現在數據文件的狀態是過舊的,就算你不加 FORCE 選項 RMAN 也是不會跳過這些數據文件的。
備庫關掉實時日誌應用,並開啟至 mount 狀態。
SQL> alter database recover managed standby database cancel;
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started
備庫登陸 RMAN, 使用 restore database (or datafile ) from service 進行恢復
RMAN> restore database from service 'primary_db'; # 這裡的 primary_db, 為備庫至主庫的 tns 連接串的別名
Starting restore at 2018-05-03 17:00:35
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=29 device type=DISK
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00001 to /data/data1/ORCL2/datafile/o1_mf_system_02t1t9ck_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:25
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00003 to /data/data1/ORCL2/datafile/o1_mf_sysaux_03t1t9d3_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:15
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00004 to /data/data1/ORCL2/datafile/o1_mf_undotbs1_04t1t9di_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:02
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00006 to /data/data1/ORCL2/datafile/o1_mf_users_05t1t9dm_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:15
Finished restore at 2018-05-03 17:01:34
當然要記得去起庫並開啟實時日誌應用進程!
1.3 12.2
在 12.2 中, Oracle 提供了一種更方便的方式去進行恢復主庫會將未記錄的塊的列表發送至備庫,並記錄在備庫控制文件中,我們可以從備庫的 v$nonlogged_block 這個視圖查看到相關信息。不需要發送主庫的整個數據文件,而是在 RMAN執行一個簡單的命令來恢復它們:
RECOVER DATABASE NONLOGGED BLOCK
停止備庫實時日誌應用
SQL> alter database recover managed standby database cancel;
備庫登陸 RMAN 執行
RECOVER DATABASE NONLOGGED BLOCK
注意:執行此步驟前請確認主備庫的 log_archive_config 參數已經設置
RMAN> recover database nonlogged block;
Starting recover at 2018-05-03 14:54:22
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=56 device type=DISK
starting recovery of nonlogged blocks
List of Datafiles
=================
File Status Nonlogged Blocks Blocks Examined Blocks Skipped
—- —— —————- ————— ————–
1 OK 0 0 107519
3 OK 0 0 262399
4 OK 0 0 149759
5 OK 0 0 31999
6 OK 0 0 42239
7 OK 0 16707 21532
8 OK 0 0 12799
9 OK 0 0 76799
18 OK 0 0 33279
19 OK 0 0 57599
20 OK 0 0 24959
21 OK 0 0 33279
22 OK 0 0 51199
23 OK 0 0 12799
29 OK 0 0 1310719
30 OK 0 0 12799
31 OK 0 0 33279
32 OK 0 0 52479
33 OK 0 0 923519
34 OK 0 16822 8777
35 OK 0 0 12799
37 OK 0 0 24959
Details of nonlogged blocks can be queried from v$nonlogged_block view
recovery of nonlogged blocks complete, elapsed time: 00:00:08
Finished recover at 2018-05-03 14:54:32
最後別忘了開啟實時日誌應用進程。
綜上來看, 12.2 中這個特性在數據倉庫等一些場景是可以嘗試的。以往我們開啟 force logging 造成大量的 redo 日誌並且影響一部分 dml 語句的執行效率。在 12.2 我們可以嘗試使用 nonlogging 操作去節省大量數據插入的時間,然後在系統空閑時間進行備庫恢復操作。但是注意這種操作也存在弊端,這樣你的備庫的可用性就大大降低了。
注意:本文內容太多,公眾號有字數限制,全文可點擊文末的閱讀原文,謝謝大家的理解。Oracle培訓和認證記得找小麥苗喲。
About Me:小麥苗
● 本文作者:小麥苗,只專註於數據庫的技術,更注重技術的運用
● 作者博客地址:http://blog.itpub.net/26736162/abstract/1/
● 本系列題目來源於作者的學習筆記,部分整理自網絡,若有侵權或不當之處還請諒解
● 版權所有,歡迎分享本文,轉載請保留出處
● 題目解答若有不當之處,還望各位朋友批評指正,共同進步