查看: 22658|回复: 54

[精华] Oracle数据库特种恢复技术(一)—原理篇

[复制链接]
论坛徽章:
5
2010新春纪念徽章
日期:2010-03-01 11:07:242012新春纪念徽章
日期:2012-01-04 11:54:26铁扇公主
日期:2012-02-21 15:03:13奥运会纪念徽章:皮划艇静水
日期:2012-09-17 16:05:02优秀写手
日期:2013-12-18 09:29:09
跳转到指定楼层
1#
发表于 2011-11-3 10:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ubotutwin 于 2012-2-1 10:03 编辑

                    Oracle数据库特种恢复技术(一)—原理篇   


                              作者:谢浩
oracle数据库特种恢复技术(二)—块内篇链接:http://www.itpub.net/thread-1507766-1-1.html
oracle数据库特种恢复技术(三)—转换篇链接:http://www.itpub.net/thread-1507774-1-1.html
Oracle数据库特种恢复技术(四)—实验篇链接:http://www.itpub.net/thread-1510202-1-1.html
oracle数据库特种恢复技术(五)--redo篇链接:http://www.itpub.net/thread-1517926-1-1.html
Oracle数据库特种恢复技术(六)—undo篇链接:http://www.itpub.net/thread-1558146-1-1.html
Oracle 数据库特种恢复技术(七)-总结篇链接:http://www.itpub.net/thread-1558154-1-1.html

      由一次ora-00600 [4000]想到的:
      项目测试库出现过一次由于异常断电引起的ora-00600 [4000]造成数据库无法启动的故障,诊断为系统回滚段数据字典(字典而不是回滚段本身)损坏,且该库处于非归档模式,无任何备份。后使用bbed修改system表空间数据文件,将相关数据块的事物状态手工修改为一致性状态,数据库得以打开。
由此引发另一种思路:如果数据库无法使用rman、冷备份、dg、ogg、dsg等方式正常恢复打开,那么还能否找回其中数据?考虑到业务数据还存在于存储设备上(只是完整性有一些缺失),能否在不启动数据库的情况下,由应用从存储设备上直接读出数据库中的业务数据?为解决以上问题,使用dba一些日常工具结合oracle数据库内部结构的知识,来分析oracle数据库定位数据的原理。这样做的目的是最终能够通过编写代码(java或者c++)实现半自动或全自动的数据库无法mount状态下的恢复。

     定位数据的方式:
    Oracle数据库服务进程在定位某行数据时,采用了数据字典+段头extent map的“集中—分散”存储模式,具体为:
              1、在数据字典中存放数据段(对应表或分区)头的物理位置
              2、在数据段头存放段中所有extent(即连续的block集合)的物理位置
      首先从数据字典入手,oracle数据库在创建时会生成一系列的基础数据字典表,这些基础字典记录了一个数据库的物理架构,oracle正是通过这些基础字典,将逻辑层的表与物理层的存储进行转换和映射。其实建库时运行的catalog.sql等脚本只是在这些基础数据字典上建立了相关的视图、同义词等(还有一些内存表的映射视图),因此catalog.sql脚本所建立的“字典”存在与否都不会影响数据库的正常运行,但基础数据字典一旦出现异常,数据库就无法启动。
oracle记录段头物理位置的字典视图是sys.dba_segments,其中记录了段头所在的文件号及在该文件中的块号,其中文件号对应文件物理位置在控制文件中查询。对于sys.dba_segments视图,最值得关心或者说与本文关系最为密切的是:

select a.owner,a.segment_name,a.header_file,a.header_block fromdba_segments a;这四个字段,通过这四个字段就可以定位某用户的某个段的段头在哪个文件的哪个数据块内。通过plsql developer等工具查看sys.dba_segments视图的定义(sqlplus也可,但作为一个成熟的dba,熟练掌握各种工具的特点,完成不同任务,最大幅度减少达成目标所需的工作量,是一项非常重要的素质),可见其数据来源于sys.sys_dba_segs视图:

create or replace view sys.dba_segments as
select owner, segment_name, partition_name,segment_type, tablespace_name,
      header_file, header_block,
      decode(bitand(segment_flags, 131072), 131072, blocks,
          (decode(bitand(segment_flags,1),1,
           dbms_space_admin.segment_number_blocks(tablespace_id, relative_fno,
           header_block, segment_type_id, buffer_pool_id, segment_flags,
           segment_objd, blocks), blocks)))*blocksize,
      decode(bitand(segment_flags, 131072), 131072, blocks,
          (decode(bitand(segment_flags,1),1,
           dbms_space_admin.segment_number_blocks(tablespace_id, relative_fno,
           header_block, segment_type_id, buffer_pool_id, segment_flags,
           segment_objd, blocks), blocks))),
      decode(bitand(segment_flags, 131072), 131072, extents,
          (decode(bitand(segment_flags,1),1,
          dbms_space_admin.segment_number_extents(tablespace_id, relative_fno,
          header_block, segment_type_id, buffer_pool_id, segment_flags,
          segment_objd, extents) , extents))),
      initial_extent, next_extent, min_extents, max_extents, pct_increase,
      freelists, freelist_groups, relative_fno,
      decode(buffer_pool_id, 0, 'DEFAULT', 1, 'KEEP', 2, 'RECYCLE', NULL)
    fromsys_dba_segs;
   
    继续观察sys.sys_dba_segs视图的定义,
create or replace view sys.sys_dba_segs
(owner, segment_name, partition_name,segment_type, segment_type_id, tablespace_id, tablespace_name, blocksize,header_file, header_block, bytes, blocks, extents, initial_extent, next_extent,min_extents, max_extents, pct_increase, freelists, freelist_groups, relative_fno,buffer_pool_id, segment_flags, segment_objd)
as
select NVL(u.name, 'SYS'), o.name, o.subname,
      so.object_type, s.type#,
      ts.ts#, ts.name, ts.blocksize,
      f.file#, s.block#,
      s.blocks * ts.blocksize, s.blocks, s.extents,
       s.iniexts * ts.blocksize,
      decode(bitand(ts.flags, 3), 1, to_number(NULL),
                                      s.extsize* ts.blocksize),
      s.minexts, s.maxexts,
      decode(bitand(ts.flags, 3), 1, to_number(NULL),
                                      s.extpct),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
             decode(s.lists, 0, 1, s.lists)),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
             decode(s.groups, 0, 1, s.groups)),
      s.file#, s.cachehint, NVL(s.spare1,0), o.dataobj#
from sys.user$ u, sys.obj$ o, sys.ts$ ts,sys.sys_objects so, sys.seg$ s,
    sys.file$ f
where s.file# = so.header_file
  ands.block# = so.header_block
  ands.ts# = so.ts_number
  ands.ts# = ts.ts#
  ando.obj# = so.object_id
  ando.owner# = u.user# (+)
  ands.type# = so.segment_type_id
  ando.type# = so.object_type_id
  ands.ts# = f.ts#
  ands.file# = f.relfile#
union all
select NVL(u.name, 'SYS'), un.name, NULL,
      decode(s.type#, 1, 'ROLLBACK', 10, 'TYPE2 UNDO'), s.type#,
      ts.ts#, ts.name, ts.blocksize, f.file#, s.block#,
      s.blocks * ts.blocksize, s.blocks, s.extents,
      s.iniexts * ts.blocksize, s.extsize * ts.blocksize, s.minexts,
      s.maxexts, s.extpct,
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
        decode(s.lists, 0, 1, s.lists)),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
        decode(s.groups, 0, 1, s.groups)),
      s.file#, s.cachehint, NVL(s.spare1,0), un.us#
from sys.user$ u, sys.ts$ ts, sys.undo$ un,sys.seg$ s, sys.file$ f
where s.file# = un.file#
  ands.block# = un.block#
  ands.ts# = un.ts#
  ands.ts# = ts.ts#
  ands.user# = u.user# (+)
  ands.type# in (1, 10)
  andun.status$ != 1
  andun.ts# = f.ts#
  andun.file# = f.relfile#
union all
select NVL(u.name, 'SYS'), to_char(f.file#) ||'.' || to_char(s.block#), NULL,
      decode(s.type#, 2, 'DEFERRED ROLLBACK', 3, 'TEMPORARY',
                      4, 'CACHE', 9, 'SPACEHEADER', 'UNDEFINED'), s.type#,
      ts.ts#, ts.name, ts.blocksize,
      f.file#, s.block#,
      s.blocks * ts.blocksize, s.blocks, s.extents,
      s.iniexts * ts.blocksize,
      decode(bitand(ts.flags, 3), 1, to_number(NULL),
                                      s.extsize* ts.blocksize),
      s.minexts, s.maxexts,
      decode(bitand(ts.flags, 3), 1, to_number(NULL),
                                     s.extpct),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
        decode(s.lists, 0, 1, s.lists)),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
        decode(s.groups, 0, 1, s.groups)),
      s.file#, s.cachehint, NVL(s.spare1,0), s.hwmincr
from sys.user$ u, sys.ts$ ts, sys.seg$ s,sys.file$ f
where s.ts# = ts.ts#
  ands.user# = u.user# (+)
  ands.type# not in (1, 5, 6, 8, 10)
  ands.ts# = f.ts#
      and s.file# = f.relfile#;
    可见其是由三个sql语句块联合而成,而其中2、3语句块明显是回滚段等segment,因此着重观察第一语句块,
select NVL(u.name, 'SYS'), o.name, o.subname,
      so.object_type, s.type#,
      ts.ts#, ts.name, ts.blocksize,
      f.file#, s.block#,
      s.blocks * ts.blocksize, s.blocks, s.extents,
       s.iniexts * ts.blocksize,
      decode(bitand(ts.flags, 3), 1, to_number(NULL),
                                      s.extsize* ts.blocksize),
      s.minexts, s.maxexts,
      decode(bitand(ts.flags, 3), 1, to_number(NULL),
                                      s.extpct),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
             decode(s.lists, 0, 1, s.lists)),
      decode(bitand(ts.flags, 32), 32, to_number(NULL),
             decode(s.groups, 0, 1, s.groups)),
      s.file#, s.cachehint, NVL(s.spare1,0), o.dataobj#
from sys.user$ u, sys.obj$ o, sys.ts$ ts,sys.sys_objects so, sys.seg$ s,
    sys.file$ f
where s.file# = so.header_file
  ands.block# = so.header_block
  ands.ts# = so.ts_number
  ands.ts# = ts.ts#
  ando.obj# = so.object_id
  ando.owner# = u.user# (+)
  ands.type# = so.segment_type_id
  ando.type# = so.object_type_id
  ands.ts# = f.ts#
      and s.file# = f.relfile#

可见其数据来源为sys.user$ u, sys.obj$ o, sys.ts$ ts, sys.sys_objects so, sys.seg$s,sys.file$ f这几个基础系统字典表(这些已经都是物理存在的表而不是视图了),而其中最重要的owner、segment_name、header_file、header_block字段,则分别来自sys.user$、sys.obj$、sys.seg$、sys.file$等字典表,也就是说要在不启动数据库的情况下定位到用户数据,必须先定位以上几个基本数据字典。那么这几个表的物理存储位置又在哪里呢?或者说在数据库不启动的情况下,如何获得这四个表的物理存储位置?要回答这个问题,先要了解一下oracle启动的过程,oracle在启动时会加载这些基础数据字典表,而这些字典表的create语句都写在sys.bootstrap$表里,

SQL> select *from sys.bootstrap$ a where a.sql_text like '%SEG$%';

     LINE#      OBJ# SQL_TEXT
---------- ------------------------------------------------------------------------------------------
        14         14 CREATE TABLE SEG$("FILE#"NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"TYPE#" NUMBE
      而sys.bootstrap$表的物理位置其实是间接“写死”在oracle代码中的。
      在每一个oracle数据库(以10g为例,其他版本相差不大)的system表空间的第一个文件的header block中都按固定结构存放有kcvfh这个结构体,其定义可以通过bbed工具查看。
这里简单介绍一下bbed工具。Bbed是oracle公司提供的一个文本编辑工具(有些dba把bbed想象的非常神秘高深,其实它就是一个普通的文本编辑器,用其他文本编辑工具(比如UltraEdit)的宏功能其实可以实现bbed的绝大部分功能),通过它可以方便的查看oracle数据在物理层面的存储结构。
      为安全考虑,先把数据库system表空间的第一个文件拷贝到另外的目录以便观察。在sqlplus中执行select file#||' '||name||' '||bytes from v$datafile ;将结果中的路径和文件名修改为先前数据文件的拷贝,用来生成bbed列表文件,这样用bbed打开的就是这份复制文件,而不是真正的库中的文件。Bbed安装编译过程不再赘述。
    进入bbed后默认偏移量是1,即file header block,
    BBED> map
     File:/home/oracle/vie.pdf (1)
     Block: 1                                     Dba:0x00400001
    ------------------------------------------------------------
     DataFile Header
   
     struct kcvfh, 676 bytes                    @0      
   
     ub4tailchk                               @8188  
    Map命令会自动检测当前数据块的type,并显示该类型数据块内所包含的数据结构信息(这也就是为什么设置不同偏移量,map输出的数据结构信息也会不同),这里看到,system表空间的file header block中包含一个名为kcvfh的结构体,该结构体占用676 bytes,深入观察:
    BBED> p kcvfh
    struct kcvfh, 676 bytes                     @0      
      struct kcvfhbfh, 20 bytes               @0      
          ub1type_kcbh                         @0        0x0b
         ub1 frmt_kcbh                        @1        0xa2
         ub1 spare1_kcbh                      @2        0x00
         ub1 spare2_kcbh                      @3        0x00
         ub4 rdba_kcbh                         @4        0x00400001
         ub4 bas_kcbh                         @8        0x00000000
         ub2 wrp_kcbh                         @12       0x0000
         ub1 seq_kcbh                         @14       0x01
         ub1 flg_kcbh                          @15       0x04 (KCBHFCKV)
         ub2 chkval_kcbh                      @16       0x2671
         ub2 spare3_kcbh                      @18       0x0000
      struct kcvfhhdr, 76 bytes               @20      
         ub4 kccfhswv                          @20       0x00000000
         ub4 kccfhcvn                         @24       0x0a200100
         ub4 kccfhdbi                         @28       0xea382478
         text kccfhdbn[0]                     @32      P
         text kccfhdbn[1]                      @33      H
         text kccfhdbn[2]                     @34      O
         text kccfhdbn[3]                     @35      N
         text kccfhdbn[4]                     @36      E
         text kccfhdbn[5]                     @37      D
         text kccfhdbn[6]                     @38      B
         text kccfhdbn[7]                     @39      
         ub4 kccfhcsq                         @40       0x00001ae3
         ub4 kccfhfsz                         @44       0x00017c00
         s_blkz kccfhbsz                      @48       0x00
         ub2 kccfhfno                         @52       0x0001
         ub2 kccfhtyp                         @54       0x0003
         ub4 kccfhacid                        @56       0x00000000
         ub4 kccfhcks                          @60       0x00000000
         text kccfhtag[0]                     @64      
         text kccfhtag[1]                     @65      
         text kccfhtag[2]                     @66      
         text kccfhtag[3]                     @67      
         text kccfhtag[4]                     @68      
         text kccfhtag[5]                     @69      
         text kccfhtag[6]                     @70      
         text kccfhtag[7]                     @71      
         text kccfhtag[8]                      @72      
         text kccfhtag[9]                     @73      
         text kccfhtag[10]                    @74      
         text kccfhtag[11]                    @75      
         text kccfhtag[12]                    @76      
         text kccfhtag[13]                    @77      
         text kccfhtag[14]                    @78      
         text kccfhtag[15]                    @79      
         text kccfhtag[16]                    @80      
         text kccfhtag[17]                     @81      
         text kccfhtag[18]                    @82      
         text kccfhtag[19]                    @83      
         text kccfhtag[20]                    @84      
         text kccfhtag[21]                    @85      
         text kccfhtag[22]                    @86      
         text kccfhtag[23]                    @87      
         text kccfhtag[24]                    @88      
         text kccfhtag[25]                    @89      
         text kccfhtag[26]                     @90      
         text kccfhtag[27]                    @91      
         text kccfhtag[28]                    @92      
         text kccfhtag[29]                    @93      
         text kccfhtag[30]                    @94      
         text kccfhtag[31]                    @95      
       ub4kcvfhrdb                            @96       0x00400179
      struct kcvfhcrs, 8 bytes                @100     
         ub4 kscnbas                          @100      0x00000008
    。。。。。。。。。。。。。。。。。
    省略后面内容
    这里的 ub4 kcvfhrdb  @96 0x00400179就是oracle启动过程中非常关键的变量:root dba,root dba中记录了sys.bootstrap$的物理位置,因此可以把root dba理解为指向sys.bootstrap$的指针。这里该变量的值为0x00400179,是按照dba(datablock address)的格式存放,将其转换为二进制后的前10位为文件号,后22位为块号 0x00400179转换为二进制0000 0000 0100 0000 0000 0001 0111 1001,文件号部分:0000 0000 01,块号部分:00 0000 0000 0001 01111001,表示1号文件的377号块,这个数字不是我的库的巧合,而是10g版本数据库的固定位置,在oracle 10g数据库启动时会默认在该偏移量的位置寻找指向sys.bootstrap$表的指针。在11g中sys.bootstrap$的位置改到了0x00400208。而10g、11g该指针的位置(即rootdba变量自己的位置)是相同的,都是file header block的96偏移量位置。需要注意的是这里的偏移量96,并不是从文件头部开始计算:oracle在建立datafile时,实际生成的文件会比管理员输入的文件尺寸大一个db_block_size的大小,比如某数据库的db_block_size=8k,建立表空间时指定某文件大小为100M,那么该文件的实际大小是100M+8K,这8K放在文件的最前面,称作os header block,root dba(也就是指向sys.bootstrap$的指针)的物理偏移量是db_block_size+96。这也就是为什么在一些使用裸设备的库上,在把裸设备交给oracle的时候,不能把文件尺寸写的和设备的尺寸完全一样,而要稍小一点,否则创建时会出现ORA-27042错误。
    这里有一个小技巧,在使用bbed分析数据文件结构时,要观察在不同主机上的不同版本的库,有些库的数据文件很大,复制、查看不便,可以针对需要,使用dd命令截取重点关注的部分,比如我在观察11g的file header block时使用 ddif=/u01/app/oracle/oradata/mydb/system01.dbf of=/home/oracle/lt140_header2.tracecount=1000 skip=0 bs=8192截取该文件的前8M数据,生成一个文件,然后传输到主要用来做分析工作的主机上,修改bbed配置文件指向该文件就能用bbed对其进行分析,这么做还有一个原因就是11g是不带bbed工具的,需要从10g复制源文件再进行编译链接。结果导向、尽量简化中间操作过程是dba工作的重要指导原则。
通过root dba的了解,已经可以在不打开数据库的情况下定位到sys.bootstrap$表的物理位置,下一个问题是,sys.bootstrap$表里存储的只是基础字典表的创建语句,那么这些表的物理存储位置是如何确定的?进一步观察sys.bootstrap$表的sql_text字段,以file$为例:SQL> set line 2000
SQL> set headoff
SQL> select *from sys.bootstrap$ a where a.obj# = 17;

        17         17
CREATE TABLEFILE$("FILE#" NUMBER NOT NULL,"STATUS$" NUMBER NOT NULL,"BLOCKS"NUMBER NOT NULL,"TS#" NUMBER,"RELFILE#"NUMBER,"MAXEXTEND" NUMBER,"INC" NUMBER,"CRSCNWRP"NUMBER,"CRSCNBAS" NUMBER,"OWNERINSTANCE"VARCHAR2(30),"SPARE1" NUMBER,"SPARE2"NUMBER,"SPARE3" VARCHAR2(1000),"SPARE4" DATE) PCTFREE 10PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0OBJNO 17 EXTENTS (FILE 1 BLOCK 113))
这个create语句的storage子句中有两个不常见的参数OBJNO 17 和EXTENTS (FILE 1 BLOCK 113),前者是指定该segment的对象号,而extents是直接指定segment的segmentheader block存储位置,我多次尝试在客户发起的sql语句中使用这两个参数未能成功,判断为只有在数据库处于特定状态或以特定身份运行时才能使用这些参数。就是说这两个参数直接指定了段在存储上得物理位置。从该参数已经可以直接定位其所对应的数据字典段头的物理位置,而oracle的段头中的extents map结构体就包涵了该段全部的数据块的物理地址。
    在sys.bootstrap$表中记录的数据字典表的create语句,还有一部分是没有直接指定存储位置的,这些表都是某个簇的成员,其实际数据存储在簇中,比如SYS.TAB$:
    CREATE TABLE TAB$("OBJ#" NUMBERNOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOTNULL,"FILE#"
。。。。。。。。。。。。。。。。。。。。省略。。。。。。。。。。。。。。。。。。。。。。。。。。。。
NUMBER,"SPARE2"NUMBER,"SPARE3" NUMBER,"SPARE4"VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE)STORAGE (  OBJNO 4 TABNO 1) CLUSTERC_OBJ#(OBJ#)
    红色字体白色背景的就是指定SYS.TAB$表加入到C_OBJ#簇中。

至此,在关闭数据库的情况下定位数据块的大致思路已经清晰,总结如下:
1、在system 表空间的第一个数据文件的特定偏移位置,找到root dba变量
2、root dba变量的值就是指向sys.bootstrap$表的物理位置的指针
3、sys.bootstrap$表中记录了数据库基础字典表的物理位置
4、基础字典表内记录了用户段段头的物理存储位置
下一步就是要通过某个段的segmentheader block从数据文件中直接读出表的数据。
论坛徽章:
3
技术图书徽章
日期:2014-06-20 16:30:312015年新春福章
日期:2015-03-04 14:53:162015年新春福章
日期:2015-03-06 11:58:39
2#
发表于 2011-11-3 10:54 | 只看该作者
支持!很全面!

使用道具 举报

回复
论坛徽章:
317
季节之章:春
日期:2012-06-20 17:38:14季节之章:夏
日期:2012-06-12 10:49:25季节之章:秋
日期:2012-06-12 10:49:25季节之章:冬
日期:2012-06-12 10:49:25马上有钱
日期:2014-06-16 15:59:19蓝色妖姬
日期:2012-05-19 11:02:10蓝色妖姬
日期:2012-06-12 11:21:48蓝色妖姬
日期:2012-06-12 11:21:48玉兔
日期:2012-07-27 11:00:12玉兔
日期:2012-08-05 10:00:09
3#
发表于 2011-11-3 11:04 | 只看该作者
好贴

使用道具 举报

回复
论坛徽章:
7
2009新春纪念徽章
日期:2009-01-04 14:52:282009日食纪念
日期:2009-07-22 09:30:002010新春纪念徽章
日期:2010-03-01 11:08:292011新春纪念徽章
日期:2011-02-18 11:43:35ITPUB十周年纪念徽章
日期:2011-11-01 16:24:04蜘蛛蛋
日期:2012-03-21 14:32:26鲜花蛋
日期:2012-05-18 09:15:29
4#
发表于 2011-11-3 11:29 | 只看该作者
不知道能存活多久,先弄下来慢慢看,哈哈

使用道具 举报

回复
论坛徽章:
9
2012新春纪念徽章
日期:2012-01-04 11:57:56鲜花蛋
日期:2012-01-28 18:56:22迷宫蛋
日期:2012-02-06 22:11:12迷宫蛋
日期:2012-02-17 15:53:03茶鸡蛋
日期:2012-04-07 19:00:55鲜花蛋
日期:2012-05-04 12:05:18奥运会纪念徽章:自行车
日期:2012-06-25 10:01:33奥运会纪念徽章:排球
日期:2012-06-27 11:19:36奥运会纪念徽章:沙滩排球
日期:2012-07-06 11:22:39
5#
发表于 2011-11-3 16:44 | 只看该作者
看起来虽然比较吃力,但还是把它看完了。。学到了不少东西

使用道具 举报

回复
论坛徽章:
10
ITPUB十周年纪念徽章
日期:2011-11-01 16:26:59马上有对象
日期:2014-02-18 16:44:082014年新春福章
日期:2014-02-18 16:44:082013年新春福章
日期:2013-02-25 14:51:24灰彻蛋
日期:2013-01-10 11:04:47ITPUB 11周年纪念徽章
日期:2012-10-09 18:16:002012新春纪念徽章
日期:2012-02-07 09:59:352012新春纪念徽章
日期:2012-01-04 11:58:18鲜花蛋
日期:2011-11-21 00:02:23马上加薪
日期:2014-04-30 16:46:19
6#
发表于 2011-11-3 17:18 | 只看该作者
顶,好文。

使用道具 举报

回复
论坛徽章:
10
八级虎吧徽章
日期:2009-02-09 17:58:50ITPUB 11周年纪念徽章
日期:2012-10-09 18:09:19蜘蛛蛋
日期:2012-01-12 13:27:03ITPUB十周年纪念徽章
日期:2011-11-01 16:24:51开发板块每日发贴之星
日期:2011-06-08 01:01:012011新春纪念徽章
日期:2011-02-18 11:43:33ITPUB9周年纪念徽章
日期:2010-10-08 09:28:532010年世界杯参赛球队:西班牙
日期:2010-06-14 22:08:542009日食纪念
日期:2009-07-22 09:30:00一汽
日期:2013-08-08 10:50:32
7#
发表于 2011-11-3 17:19 | 只看该作者
强大哦

使用道具 举报

回复
论坛徽章:
0
8#
发表于 2011-11-4 15:33 | 只看该作者
好文,绝对要支持

使用道具 举报

回复
论坛徽章:
73
2010新春纪念徽章
日期:2010-03-01 11:06:132011新春纪念徽章
日期:2011-02-18 11:43:332012新春纪念徽章
日期:2012-01-04 11:55:422013年新春福章
日期:2013-02-25 14:51:242014年新春福章
日期:2014-02-18 16:44:08马上有车
日期:2015-01-19 09:45:33最佳人气徽章
日期:2012-03-13 17:39:18ITPUB季度 技术新星
日期:2012-11-27 10:16:10问答徽章
日期:2013-10-23 15:13:22林肯
日期:2013-11-02 08:34:46
9#
发表于 2011-11-4 15:47 | 只看该作者
果断mark

使用道具 举报

回复
论坛徽章:
1
2010新春纪念徽章
日期:2010-03-01 11:20:04
10#
发表于 2011-11-7 14:34 | 只看该作者
高手写的东西果然与众不同

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表