其实一句话就可以说明白:那就是数据文件的头上不仅包含了checkpoint_change#,更重要的是它包含了这个checkpoint_change#所在的logfile的sequence#,准确的说是rba。有了rba,在恢复时就能准确的知道到底需要哪个logfile(archivelog or redo)。
结果花了很大篇幅,只想以试验的方式做个简单的验证,便于大家理解。欢迎拍砖!
另外提个问题:是否存在一些数据字典它是源于redo的?

--controlfile中记录的checkpoint_change#
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1951985
--datafile中记录的checkpoint_change#
SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
--controlfile中记录的每一个datafile的checkpoint_change#
SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
--controlfile中记录的redo的checkpoint_change#
SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1951985 2008/10/01 14:17:00

SQL> alter system checkpoint;

系统已更改。
--检查点发生之后,上面提到的checkpoint_change#都给更新
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1955601

SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26

SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26

SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955601 2008/10/01 16:15:26

SQL> shutdown immediate
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
--冷备份db,为下面的恢复试验使用
SQL> startup mount
ORACLE 例程已经启动。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes
数据库装载完毕。
--查看备份时刻的checkpoint_change#,此时的checkpoint_change#=1955692
是实例shutdown时系统所做的完全检查点对应的checkpoint_change#,下面
在恢复时还会看到这个checkpoint_change#:1955692
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1955692

SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24

SQL> alter database open;

数据库已更改。
--输入测试数据,验证备份恢复的过程,注意仔细观查插入到tt表中的dbms_flashback.get_system_change_number
和v$log中的FIRST_CHANGE#之间的关系,我们通常理解备份恢复的原理是:事务对应的scn如果落在了哪个archivelog
里,那么这个archivelog在恢复时就被用到,下面的大致试验过程也会验证这一点:
SQL> connect test/test
已连接。
SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 INACTIVE                 74 YES       1926639
         2 CURRENT                  76 NO        1951985
         3 INACTIVE                 75 YES       1947901

SQL> truncate table tt;

表被截断。

SQL> desc tt
名称                                      是否为空? 类型
----------------------------------------- -------- ----------------------------

ID                                                 NUMBER(38)
NAME                                               VARCHAR2(10)

SQL> insert into tt values(dbms_flashback.get_system_change_number,'a');

已创建 1 行。

SQL> commit;

提交完成。

SQL> connect / as sysdba
已连接。
--datafile header上记录的rba信息,rba的意义在下面做了详细解释,这里只需
知道FHRBA_SEQ表示redo的sequence#=76对应的是当前联机日志,而该sequence#被
记录在了datafile header上
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         76       6618         16
         2         76       6618         16
         3         76       6618         16
         4         76       6618         16

SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 INACTIVE                 74 YES       1926639
         2 CURRENT                  76 NO        1951985
         3 INACTIVE                 75 YES       1947901
SQL> insert into test.tt values(dbms_flashback.get_system_change_number,'b');

已创建 1 行。

SQL> commit;

提交完成。

SQL> alter system switch logfile;

系统已更改。

SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 CURRENT                  77 NO        1956233
         2 ACTIVE                   76 YES       1951985
         3 INACTIVE                 75 YES       1947901

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         76       6618         16
         2         76       6618         16
         3         76       6618         16
         4         76       6618         16

SQL> alter system checkpoint;

系统已更改。

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         77          9         16
         2         77          9         16
         3         77          9         16
         4         77          9         16

SQL> select * from test.tt;

ID NAME
---------- ----------
   1956113 a
   1956225 b

SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 CURRENT                  77 NO        1956233
         2 INACTIVE                 76 YES       1951985
         3 INACTIVE                 75 YES       1947901

SQL> insert into test.tt values(dbms_flashback.get_system_change_number,'c');

已创建 1 行。

SQL> commit;

提交完成。

SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 CURRENT                  77 NO        1956233
         2 INACTIVE                 76 YES       1951985
         3 INACTIVE                 75 YES       1947901

SQL> alter system switch logfile;

系统已更改。

SQL> select * from test.tt;

ID NAME
---------- ----------
   1956113 a
   1956225 b
   1956317 c

SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 ACTIVE                   77 YES       1956233
         2 INACTIVE                 76 YES       1951985
         3 CURRENT                  78 NO        1956324
SQL> insert into test.tt values(dbms_flashback.get_system_change_number,'d');

已创建 1 行。

SQL> commit;

提交完成。

SQL> alter system switch logfile;

系统已更改。

SQL> select * from test.tt;

ID NAME
---------- ----------
   1956113 a
   1956225 b
   1956317 c
   1956472 d
--总共往tt表里插入了4条数据,对应的id值(通过dbms_flashback.get_system_change_number获得的)
都大于sequence#=76所对应的first_change#:1951985,因此在恢复db时
sequence#=76的归档日志会被用到,还会用到那些归档日志呢?
要看tt表中对应的id值落在了那些归档日志的FIRST_CHANGE#和NEXT_CHANGE#之内,
如果落在其中,则恢复时这个归档日志就会被用到,就这个例子而言,76,77,78号归档日志
在恢复db时都会被用到,接下来的恢复过程也会验证这一点
SQL> select sequence#,first_change#,next_change#  from v$archived_log
  2  where sequence# in (76,77,78) and resetlogs_id=666280390;

SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
---------- ------------- ------------
        76       1951985      1956233
        77       1956233      1956324
        78       1956324      1956480
--通过dump datafile header中的信息发现datafile header上不仅记录了checkpoint_change#,
更重要的是记录了checkpoint_change#所在的redo sequence#:
SQL> alter session set events 'immediate trace name FILE_HDRS level 12';

会话已更改。
trace file中最有用的信息莫过于:
Checkpointed at scn:  0x0000.001dd9e4 10/01/2008 16:30:40 --checkpoint_change#
thread:1 rba:(0x4e.2.10) --sequence# (rba的含义在下面会有详细介绍)
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         79          2         16
         2         79          2         16
         3         79          2         16
         4         79          2         16

SQL> shutdown immediate
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
--拷贝备份的datafile回来
SQL> startup
ORACLE 例程已经启动。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes
数据库装载完毕。
ORA-01113: 文件 1 需要介质恢复
ORA-01110: 数据文件 1: 'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF'

--为什么会发出"文件 1 需要介质恢复"这样的提示,是因为controlfile
中记录的checkpoint_change#是:1967625,而datafile header上记录的
checkpoint_change#是:1955692
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1967625

SQL> select checkpoint_change# ,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change# ,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1967625 2008/10/01 19:06:21
           1967625 2008/10/01 19:06:21
           1967625 2008/10/01 19:06:21
           1967625 2008/10/01 19:06:21

SQL> select checkpoint_change# ,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1967625 2008/10/01 19:06:21
--下面通过dump datafile header中的信息来观查checkpoint_change#和rba的信息,来看看
oracle到底在恢复时是如何使用归档日志的。
SQL> alter session set events 'immediate trace name FILE_HDRS level 12';

会话已更改。
trace file中每个datafile都有一段对应的描述,内容摘录如下:
DATA FILE #1: 
  (name #7) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF
...............................中间无关内容省略
--==================================
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--oracle在恢复时最有用的就是Checkpointed at scn:0x0000.001dd76c和
thread:1 rba:(0x4c.19da.10)了
--======================================
DATA FILE #2: 
  (name #1) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\TEST.DBF
....................................中间无关内容省略
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--=======================================
DATA FILE #3: 
  (name #5) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSAUX01.DBF
....................................中间无关内容省略
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--=======================================
DATA FILE #4: 
  (name #6) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\UNDOTBS01.DBF
....................................中间无关内容省略
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--=======================================
--而上面trace file中记录的Checkpointed at scn:0x0000.001dd76c
转化为10进制数:
SQL> select to_number('001dd76c','xxxxxxxx') from dual;

TO_NUMBER('001DD76C','XXXXXXXX')
--------------------------------
                         1955692

而1955692正是我们在最开始备份时记录下来的checkpoint_change#,另外检查点发生的时间其实也是
吻合的:10/01/2008 16:17:24,也许有人说查询:
select checkpoint_change#,checkpoint_time from v$datafile_header;
其实读取的就是数据文件头,结果当然是一样的,呵呵,没错,不论是上面查询还是dump datafile header
其实信息的来源都是来自datafile header。只是dump出来我们看的更加直观一些,其实在数据字典中也提供了
类似的信息,如上面执行的查询:
select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;
为什么要查询x$kcvfh,是因为x$kcvfh是v$datafile_header的源,这个大家可以查看
v$fixed_view_definition而得知。
其实fhrba_seq,fhrba_bno,fhrba_bof这3个字段对应的就是rba,rba的意思是:
Recent entries in the redo thread of an Oracle instance are addressed using a 3-part redo byte address, or RBA. An RBA is comprised of 
the log file sequence number (4 bytes) 
the log file block number (4 bytes) 
the byte offset into the block at which the redo record starts (2 bytes) 
在datafile header上记录rba,在恢复时就能非常准确的知道需要哪个日志文件(通过the log file sequence number)以及哪个block(通过the log file block number)以及
在这个日志block上从哪个byte开始读取恢复(通过the byte offset)
--=========================================
下面我们来接着上面打开db时的提示来恢复db,验证一下:
SQL> alter database open;
alter database open
*
第 1 行出现错误:
ORA-01113: 文件 1 需要介质恢复
ORA-01110: 数据文件 1: 'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF'

SQL> recover database;
ORA-00279: 更改 1955692 (在 10/01/2008 16:17:24 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

76_%U_.ARC
ORA-00280: 更改 1955692 (用于线程 1) 在序列 #76 中

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

--====================================
--这里为什么会从1955692开始恢复db,原因当然就是备份时db发生检查点
其对应的checkpoint_change#是1955692,这个我们在最开始的时候就提到过,说
在备份时会用到这个值:1955692,那么序列#76就是如何来的呢?
其实就是从rba转化来得:备份时候datafile header的dump信息上面已经显示出来了,
其实rba是:thread:1 rba:(0x4c.19da.10)
根据rba表示的意义把4c转化成10进制数不正是:4*16+12(16进制的c)=76
,那么sequence#=76的归档日志文件O1_MF_1_76_%U_.ARC其实并不会在恢复时完全用到,而是从
block:19da转化为10进制数是:
SQL> select to_number('19da','xxxx') from dual;

TO_NUMBER('19DA','XXXX')
------------------------
                    6618
也就是从6618#block开始恢复
下面开始恢复:
--========================================
接着上面要求恢复的提示敲回车:
ORA-00279: 更改 1956233 (在 10/01/2008 16:27:12 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

77_%U_.ARC
ORA-00280: 更改 1956233 (用于线程 1) 在序列 #77 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_76_4G6F313F_.ARC'

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

--====================================
sequence#=76的日志已经恢复,接下来需要77#日志:
恢复时到底需要那些归档日志可以通过查看 v$recovery_log来获得:
v$recovery_log的信息就是通过比较control file中的checkpoint_change#
和datafile header上的checkpoint_change#而产生的,如果我们在恢复时
把备份的controlfile和datafile一同拷贝回来(不要拷贝redo),那么肯定在
v$recovery_log不会查到任何信息。
SQL> select sequence# from v$recovery_log;

SEQUENCE#
----------
        77
        78

SQL>
在76#归档日志恢复之后再来观察一下数据文件头上checkpoint_change#和rba的变化情况:
checkpoint_change#信息:
SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1956233 2008/10/01 16:27:12
           1956233 2008/10/01 16:27:12
           1956233 2008/10/01 16:27:12
           1956233 2008/10/01 16:27:12

SQL>
rba信息:
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         77          2          0
         2         77          2          0
         3         77          2          0
         4         77          2          0

SQL>
此时再恢复db时会使用sequence#=77的归档日志,同时是从第二个日志block
开始使用的,因为日志文件头占用1个block,如果有人通过dd命令做过redo file
从文件系统和raw转化的话应该知道redo的头占用1个block,不过这个可能也和os有关的
,不同的os,redo的头块也可能会占用不同个数的block,具体没有做过太深入的研究。
--==========================
接着恢复:
ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用于线程 1) 在序列 #78 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

--==========================
查询一下checkpoint_change#和rba的信息:
上面通过查询view验证过了,这次dump 一下datafile header来看看:
SQL> alter session set events 'immediate trace name FILE_HDRS level 12';

会话已更改。
--=======================
trace file 主要信息:(仅摘录一个文件的信息,4个文件的信息其实都相同)
DATA FILE #1: 
  (name #7) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF
..........................................(省去无关的信息)
Checkpointed at scn:  0x0000.001dd9e4 10/01/2008 16:30:40
thread:1 rba:(0x4e.2.0)
--=======================
这里只转化一下sequence#:4e看看是否是78就可以了:
4*16+14(16进制的e)=78
正好是78,也就是恢复时下一个要使用的归档日志。
--=============================
接着恢复:
ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用于线程 1) 在序列 #78 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

已应用的日志。
完成介质恢复。
SQL>
--===================================
78#归档日志恢复之后checkpoint_change#可以达到1956480,通过下面查询78#
归档日志的next_change#可以得知:
SQL> select sequence#,first_change#,next_change#  from v$archived_log
  2  where sequence# in (76,77,78) and resetlogs_id=666280390;

SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
---------- ------------- ------------
        76       1951985      1956233
        77       1956233      1956324
        78       1956324      1956480

SQL>
但目前datafile header的checkpoint_change#和rba信息是:
1967624以及81       1281         16,是因为在恢复时系统
自动读取了联机日志。
SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1967624 2008/10/01 19:06:21
           1967624 2008/10/01 19:06:21
           1967624 2008/10/01 19:06:21
           1967624 2008/10/01 19:06:21

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         81       1281         16
         2         81       1281         16
         3         81       1281         16
         4         81       1281         16

SQL> select group#,status,sequence#,archived,first_change# from v$log;

GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 INACTIVE                 80 YES       1961750
         3 CURRENT                  81 NO        1967088
         2 INACTIVE                 79 YES       1956480

SQL>
--oracle为什么能自动读取redo来恢复,是因为在controlfile中记录了redo的信息
SQL> select sequence#,checkpoint_change#,last_redo_change# from v$thread;

SEQUENCE# CHECKPOINT_CHANGE# LAST_REDO_CHANGE#
---------- ------------------ -----------------
        81            1967625           1967375

SQL>
--下面把最新的redo暂时隐藏起来,也就是说不让其自动应用redo再来观查一下
oracle是如何要寻找redo的:
SQL> shutdown immediate
ORA-01109: 数据库未打开

已经卸载数据库。
ORACLE 例程已经关闭。
--拷贝备份的数据文件,同时把redo隐藏起来
SQL> startup
ORACLE 例程已经启动。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes
数据库装载完毕。
ORA-01113: 文件 1 需要介质恢复
ORA-01110: 数据文件 1: 'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF'

SQL> recover database;
ORA-00279: 更改 1955692 (在 10/01/2008 16:17:24 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

76_%U_.ARC
ORA-00280: 更改 1955692 (用于线程 1) 在序列 #76 中

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

ORA-00279: 更改 1956233 (在 10/01/2008 16:27:12 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

77_%U_.ARC
ORA-00280: 更改 1956233 (用于线程 1) 在序列 #77 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_76_4G6F313F_.ARC'

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用于线程 1) 在序列 #78 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}

ORA-00283: 恢复会话因错误而取消
ORA-00313: 无法打开日志组 2 (用于线程 1) 的成员
ORA-00312: 联机日志 2 线程 1:
'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO02.LOG'
ORA-27041: 无法打开文件
OSD-04002: 无法打开文件
O/S-Error: (OS 2) 系统找不到指定的文件。

ORA-01112: 未启动介质恢复
--oracle为什么会找REDO02.LOG,因为REDO02.LOG对应的sequence#是79,看看在controlfile中记录的redo信息就知道了
,v$log的信息来自controlfile,这也说明了为什么我们在恢复db时如果controlfile是最新的话那么在恢复时redo会被自动应用,而
当controlfile是从备份中恢复过来(也就是说controlfile不是最新的,是备份的,在恢复时需要使用using backup controlfile子句)
的话在恢复db时redo不会被自动应用,而需要我们手动输入来尝试看看oracle到底需要哪个redo

SQL> select group#,status,sequence#,first_change# from v$log;

GROUP# STATUS            SEQUENCE# FIRST_CHANGE#
---------- ---------------- ---------- -------------
         1 INACTIVE                 80       1961750
         3 CURRENT                  81       1967088
         2 INACTIVE                 79       1956480

SQL>
--============================
验证一下使用using backup controlfile自己恢复db时使用redo的情况:
SQL> shutdown immediate
ORA-01109: 数据库未打开

已经卸载数据库。
ORACLE 例程已经关闭。
SQL>
--拷贝备份的datafile and controlfile以及最新的redo回来
SQL> startup
ORACLE 例程已经启动。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes
数据库装载完毕。
ORA-00314: 日志 1 (用于线程 1) 要求的序号  与  不匹配
ORA-00312: 联机日志 1 线程 1:
'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO01.LOG'

SQL>
为什么在open db时会发出这样的提示:
看看controlfile and datafile_header中记录的checkpoint_change#:
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1955692

SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         76       6618         16
         2         76       6618         16
         3         76       6618         16
         4         76       6618         16

SQL> select group#,status,sequence#, first_change# from v$log;

GROUP# STATUS            SEQUENCE# FIRST_CHANGE#
---------- ---------------- ---------- -------------
         1 INACTIVE                 74       1926639
         3 INACTIVE                 75       1947901
         2 CURRENT                  76       1951985
--很显然v$log的信息是来自controlfile的,和上面新的controlfile中记录的
v$log的信息对比,当然doc上也明确提到v$log的信息来自controlfile
从上面的查询看出来controlfile和datafile中记录的checkpoint_change#都是1955692
,而且controlfile中记录的redo的checkpoint_change#也是1955692;但是再来看看redo中记录的
checkpoint_change#又是多少呢?
我发现redo header上并不会记录checkpoint_change#,这一点大家可以验证,当然
当checkpoint发生时很多doc上都提到会把当前的scn更新到controlfile和datafile header上,
并没有提到会更新再redo的头上。
SQL> alter session set events 'immediate trace name REDOHDR level 12';

会话已更改。

SQL>
从下面的trace file中我们知道大致判断LOG FILE #1(#2,#3)这一段的信息
和controlfile中记录的一致,我在这里认定LOG FILE #1(#2,#3)这段信息是来自controlfile中:从seq(sequence#)就可以判断出来:0x0000004a,0x0000004c,0x0000004b
分别对应10进制的74,76,75,而且LOG FILE #2的Next scn: 0xffff.ffffffff,说明它表示是当前redo,这些内容都和controlfile中记录的完全一致;
但是从 FILE HEADER:这一段开始发现它的内容才是真真来自redo:
因为LOG FILE #1(#2,#3)对应的Seq#分别是: 0000000080,0000000079,0000000081
而且LOG FILE #3的Next scn: 0xffff.ffffffff,说明它表示是当前redo
那么在redo的header上是否记录controlfile的信息呢,应该不记录,这里是这条命令:
alter session set events 'immediate trace name REDOHDR level 12';执行时要
从controlfile里读取redo的路径以及一些相关信息(就是LOG FILE #1(#2,#3)这一段)从而再到redo的header上真真
读取redo的内容。由于controlfile中记录的redo的信息和redo header上记录的信息不符,所以打开db时出现了上面的提示:
"ORA-00314: 日志 1 (用于线程 1) 要求的序号  与  不匹配
ORA-00312: 联机日志 1 线程 1:
'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO01.LOG'"

trace file的信息如下:
--==================================
LOG FILE #1: 
  (name #2) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO01.LOG
Thread 1 redo log links: forward: 2 backward: 0
siz: 0x2000 seq: 0x0000004a hws: 0x4 bsz: 512 nab: 0x4eb flg: 0x1 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.001d6386
Low scn: 0x0000.001d65ef 09/30/2008 23:04:54
Next scn: 0x0000.001db8fd 10/01/2008 12:59:45
FILE HEADER:
        Compatibility Vsn = 169869568=0xa200100
        Db ID=1963034992=0x75018970, Db Name='TEST'
        Activation ID=1964389871=0x751635ef
        Control Seq=3855=0xf0f, File size=8192=0x2000
        File Number=1, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000080, SCN 0x0000001def16-0x0000001e03f0"
thread: 1 nab: 0x1ffd seq: 0x00000050 hws: 0x2 eot: 0 dis: 0
reset logs count: 0x27b6a1c6 scn: 0x0000.0015dd61
Low scn: 0x0000.001def16 10/01/2008 17:16:54
Next scn: 0x0000.001e03f0 10/01/2008 19:00:41
Enabled scn: 0x0000.0015dd61 09/24/2008 13:53:10
Thread closed scn: 0x0000.001def16 10/01/2008 17:16:54
Disk cksum: 0x2a74 Calc cksum: 0x2a74
Terminal Recovery Stop scn: 0x0000.00000000
Terminal Recovery Stamp  01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 315 blocks
Miscellaneous flags: 0x0
Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000
LOG FILE #2: 
  (name #3) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO02.LOG
Thread 1 redo log links: forward: 3 backward: 1
siz: 0x2000 seq: 0x0000004c hws: 0x2 bsz: 512 nab: 0x19da flg: 0x8 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.001db8fd
Low scn: 0x0000.001dc8f1 10/01/2008 14:17:00
Next scn: 0xffff.ffffffff 01/01/1988 00:00:00
FILE HEADER:
        Compatibility Vsn = 169869568=0xa200100
        Db ID=1963034992=0x75018970, Db Name='TEST'
        Activation ID=1964389871=0x751635ef
        Control Seq=3850=0xf0a, File size=8192=0x2000
        File Number=2, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000079, SCN 0x0000001dda80-0x0000001def16"
thread: 1 nab: 0x1ffd seq: 0x0000004f hws: 0x2 eot: 0 dis: 0
reset logs count: 0x27b6a1c6 scn: 0x0000.0015dd61
Low scn: 0x0000.001dda80 10/01/2008 16:35:11
Next scn: 0x0000.001def16 10/01/2008 17:16:54
Enabled scn: 0x0000.0015dd61 09/24/2008 13:53:10
Thread closed scn: 0x0000.001dda80 10/01/2008 16:35:11
Disk cksum: 0xe55a Calc cksum: 0xe55a
Terminal Recovery Stop scn: 0x0000.00000000
Terminal Recovery Stamp  01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 227 blocks
Miscellaneous flags: 0x0
Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000
LOG FILE #3: 
  (name #4) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO03.LOG
Thread 1 redo log links: forward: 0 backward: 2
siz: 0x2000 seq: 0x0000004b hws: 0x3 bsz: 512 nab: 0x1ffd flg: 0x1 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.001d65ef
Low scn: 0x0000.001db8fd 10/01/2008 12:59:45
Next scn: 0x0000.001dc8f1 10/01/2008 14:17:00
FILE HEADER:
        Compatibility Vsn = 169869568=0xa200100
        Db ID=1963034992=0x75018970, Db Name='TEST'
        Activation ID=1964389871=0x751635ef
        Control Seq=3859=0xf13, File size=8192=0x2000
        File Number=3, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000081, SCN 0x0000001e03f0-0xffffffffffff"
thread: 1 nab: 0x501 seq: 0x00000051 hws: 0x2 eot: 1 dis: 0
reset logs count: 0x27b6a1c6 scn: 0x0000.0015dd61
Low scn: 0x0000.001e03f0 10/01/2008 19:00:41
Next scn: 0xffff.ffffffff 01/01/1988 00:00:00
Enabled scn: 0x0000.0015dd61 09/24/2008 13:53:10
Thread closed scn: 0x0000.001e0609 10/01/2008 19:06:21
Disk cksum: 0x9c26 Calc cksum: 0x9c26
Terminal Recovery Stop scn: 0x0000.00000000
Terminal Recovery Stamp  01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 219 blocks
Miscellaneous flags: 0x0
Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000
--=============================================
下面恢复一下db:
SQL> recover database using backup controlfile;
ORA-00279: 更改 1955692 (在 10/01/2008 16:17:24 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

76_%U_.ARC
ORA-00280: 更改 1955692 (用于线程 1) 在序列 #76 中

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}
auto
ORA-00279: 更改 1956233 (在 10/01/2008 16:27:12 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

77_%U_.ARC
ORA-00280: 更改 1956233 (用于线程 1) 在序列 #77 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_76_4G6F313F_.ARC'

ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用于线程 1) 在序列 #78 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'

ORA-00279: 更改 1956480 (在 10/01/2008 16:35:11 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

79_%U_.ARC
ORA-00280: 更改 1956480 (用于线程 1) 在序列 #79 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_78_4G6FL06C_.ARC'

ORA-00279: 更改 1961750 (在 10/01/2008 17:16:54 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

80_%U_.ARC
ORA-00280: 更改 1961750 (用于线程 1) 在序列 #80 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_79_4G6J06PY_.ARC'

ORA-00279: 更改 1967088 (在 10/01/2008 19:00:41 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

81_%U_.ARC
ORA-00280: 更改 1967088 (用于线程 1) 在序列 #81 中
ORA-00278: 此恢复不再需要日志文件
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_80_4G6P2T6T_.ARC'

ORA-00308: 无法打开归档日志
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_81_%U_.ARC'
ORA-27041: 无法打开文件
OSD-04002: 无法打开文件
O/S-Error: (OS 2) 系统找不到指定的文件。

SQL>
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         81          2          0
         2         81          2          0
         3         81          2          0
         4         81          2          0
SQL> select sequence#,last_redo_sequence# from v$thread;

SEQUENCE# LAST_REDO_SEQUENCE#
---------- -------------------
        76                  76

SQL>
--目前datafile header上的sequence#是81,也就是恢复db接下来需要的redo sequence#是81,也就是当前redo:group 3;
而controlfile中记录的是76,因此当controlfile不是最新时,此时恢复db是无法自动应用redo,就是这个道理,
需要我们挨个输入redo来尝试,当然前面已经对redo的header进行了dump,我们
知道81的redo是group 3,接着恢复,并且输入group 3对应的redo的路径和名称:
SQL> recover database using backup controlfile;
ORA-00279: 更改 1967088 (在 10/01/2008 19:00:41 生成) 对于线程 1 是必需的
ORA-00289: 建议:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

81_%U_.ARC
ORA-00280: 更改 1967088 (用于线程 1) 在序列 #81 中

指定日志: {<RET>=suggested | filename | AUTO | CANCEL}
E:\oracle\product\10.2.0\oradata\test\redo03.log
已应用的日志。
完成介质恢复。
SQL> alter database open  resetlogs;

数据库已更改。

SQL>

揭密备份恢复的原理!相关推荐

  1. mysql的备份恢复原理_MySQL备份恢复-mysqldump原理

    +++++++++++++++++++++++++++++++++++++++++++ 标题:mysqldump对MySQL数据库备份恢复原理 时间:2019年2月23日 内容:mysqldump工具 ...

  2. 数据库误操作后悔药来了:AnalyticDB PostgreSQL教你实现分布式一致性备份恢复

    简介:本文将介绍AnalyticDB PostgreSQL版备份恢复的原理与使用方法. 一.背景 AnalyticDB PostgreSQL版(简称ADB PG)是阿里云数据库团队基于PostgreS ...

  3. Sql Server数据库备份和恢复:原理篇

    本文与您探讨为什么Sql Server有完整备份.差异备份和事务日志备份三种备份方式,以及为什么数据库又有简单模式.完整模式和大容量日志模式这三种恢复模式.本文内容适用于2005以上所有版本的Sql ...

  4. mysql备份恢复专题二(Xtrabackup全库完全恢复原理)

    mysql完全恢复原理 创建测试库 # mysql -uroot -pR00t_123 mysql>create database test; mysql> show databases ...

  5. 备份集过期时间_TiDB备份恢复方式你知多少?

    背景 学习一款数据库,要学会备份和恢复.备份是一个严谨的工作,作为一个dba,掌握数据库备份.恢复的各种手段. 下面让我们一起来看看TiDB的备份恢复有那些手段吧. 基于MVCC的恢复方式 相关原理已 ...

  6. mysql 数据库 xtrabackup (完全备份恢复,恢复后重启失败总结)

    一. 完全备份恢复说明 xtrabackup二进制文件有一个xtrabackup --copy-back选项,它将备份复制到服务器的datadir目录下.下面是通过 --target-dir 指定完全 ...

  7. Window环境下配置MySQL 5.6的主从复制、备份恢复

    Window环境下配置MySQL 5.6的主从复制.备份恢复 1.环境准备 Windows 7 64位 MySQL 5.6 主库:192.168.103.207 从库:192.168.103.208 ...

  8. 【备份恢复】Oracle 数据备份与恢复微实践

    <Oracle 数据备份与恢复微实践> 新年新群招募: 中国Oracle精英联盟170513055 群介绍:本群是大家的一个技术分享社区,在这里可以领略大师级的技术讲座,还有机会参加Ora ...

  9. Mysql数据备份恢复及主从同步

    目录 Mysql备份及主从同步 Mysql备份 1. mysqldump全量备份 2.log_bin增量备份 Mysql主从同步配置 1.1主从同步过程 1.2 配置 Mysql备份及主从同步 Mys ...

  10. linux存储pdf伟岸_Linux 文件恢复的原理

    inode 和 block 首先简单介绍一下 Linux 文件系统的最基本单元:inode.inode 译成中文就是索引节点,每个存储设备(例如硬盘)或存储设备的分区被格式化为文件系统后,应该有两部份 ...

最新文章

  1. 2022-2028年中国可生物降解农用薄膜产业竞争现状及投资决策建议报告
  2. 软件框架设计的艺术----读书总结
  3. vue.js - advance - render 函数小抄
  4. vue开发入门篇(二)-axios POST提交数据的三种请求方式写法
  5. zabbix_监控_进程
  6. JQuery操作checkbox、radio
  7. DIV周边添加投影及背景固定
  8. 新手做自媒体运营了解这几个步骤,运营效率提高5倍!(附教程)
  9. Graph Search就是语义搜索
  10. pip更换源 windows10_Conda及Pip换源处理
  11. mysql优化--叶金荣老师讲座笔记
  12. deebot扫地机器人响四声_中国智能扫地机器人重点制造基地企业名录(2020年版)...
  13. Verilog 语法点使用————(持续更新)
  14. 网络推手团队_辛8工作室,被列入经营异常名单!工作室发声明解释!二子爷喊话辛8:你能强大过马云吗?达少太忙没有时间玩!团队断水断粮式野外生存!...
  15. 浅析指针(pointer)与引用(reference)
  16. java 中文 语义分析,了解Javac编译器 - xinlan1964的个人页面 - OSCHINA - 中文开源技术交流社区...
  17. Python解压zip和rar文件
  18. Lookup Transformation
  19. iOS 自定义页面的切换动画与交互动画 By Swift
  20. Android M 动态权限获取

热门文章

  1. 鸿蒙系统手机电脑互传文件,【手机篇】巧借局域网,便捷实现手机电脑间的文件传输...
  2. 人生就是个学习、思考与实践的过程
  3. 生成时间序列每月月初月末
  4. java lazy_在Java8中模拟Lazy
  5. Matlab入门:实现简单的数据剔除
  6. 计算机上瘾英语对话,对手机上瘾的英语作文(精选5篇)
  7. 天才黑客 Flanker 疑因拒绝做黑客攻击业务,被拼多多强行辞退,错失上亿股票...
  8. 嵌入式开发 学习指导
  9. Android 获取手机充电状态
  10. 收集广州周边徒步线路