• 高性能Linux服务器 第6章 ext3文件系统反删除利器ext3grep extundelete工具恢复rm -rf 误删除的文件


    高性能Linux服务器 第6章  ext3文件系统反删除利器ext3grep  extundelete工具恢复rm -rf 误删除的文件

    只能用于ext3文件系统!!!!!!!高俊峰(高性能Linux服务器构建实战:运维监控、性能调优与集群应用(完整))

    Linux作为企业级服务器,数据的安全性至关重要,任何数据的丢失和误删除都是不可容忍的。作为系统管理员,一定要有数据保护意识,不但要对服务器数据进行定期备份,而且还要具有误删除数据后将其快速恢复的技能。本章重点讲述Linux下的ext3文件系统中用于数据恢复的开源软件ext3grep。通过这个软件,可以快速、准确地恢复误删除的数据。最后,通过两个实例具体介绍利用ext3grep恢复数据的详细过程。

    6.1“rm-rf”带来的困惑

    国外一份非常著名的Linux系统管理员守则中有这么一条:“慎用rm-rf命令,除非你知道此命令将带来什么后果”。可见,这个命令对系统管理员的重要性。在实际的工作中,由此命令带来的误删除数据的案例屡见不鲜,很多系统管理员都遇到过或者犯过这样的错误。由于开发人员对命令不熟悉,或者粗心大意、疏于管理,执行了此命令,数据在一瞬间就被清空了。Linux不具备类似回收站的功能,这就意味着数据会丢失。虽然Linux自身提供了恢复数据的机制,但是这个功能基本没用,要恢复数据,通过常规手段是无法完成的,此时,只有找专业的数据恢复公词来恢复数据,这样无疑要付出很大的成本,造成无法估量的损失。

    可见,作为系统管理员,一定要有数据安全意识,数据保护意识,严格遵守相关维护守则,将这种失误带来的损失降低到最低。幸运的是,Linux下提供了一款恢复误删数据的开源软件,利用这个ext3文件系统数据恢复工具ext3grep可以恢复误删除的数据。

    6.2  ext3grep的安装与使用

        ext3grep是一个开源的ext3文件系统反删除工具。在ext3grep出现之前,数据被删除后,通过常规手段恢复基本上是不可能的,虽然debugfs命令可以对ext2文件系统做一些恢复,但是对ext3文件系统就无能为力了。ext3是一个日志型文件系统,ext3grep正是通过分析ext3文件系统的日志信息来恢复被删除的文件和数据的。

    6.2.1  ext3grep的恢复原理

    在介绍ext3grep恢复原理之前,先介绍一下文件系统中inode的一些相关知识。inode是文件系统组成的最基本单元,是文件系统连接任何子目录、任何文件的桥梁。它包括了文件系统中文件基本属性和存放数据的位置等相关信息。每个文件由两部分组成:一部分是inode,另一部分是block。block用来存储数据,inode用来存储数据索引信息,包括文件大小、读写权限、属主、归属的用户组等。操作系统根据用户指令,通过inode值就能很快找到对应的文件。

    打个比方,存储设备或磁盘区分就相当于一本书,block相当于书中的每一页,inode相当于这本书的目录。一本书有很多内容,要查找某部分的内容,先查找目录,然后就能很快定位到想要查看的内容。

    在Linux下可以通过“ls-id”命令来查看某个文件或者目录的inode值。例如查看根目录的inode值,可以输入:

    [root@localhost /]#lsid   /
    2 /
    [root@steven ~]# ls -id /boot
    2 /boot

    由此可知,根目录的inode值为2。

    利用ext3grep恢复文件时并不依赖特定文件格式。首先ext3grep通过文件系统的、root inode(根目录的inode一般为2来获得当前文件系统下所有文件的信息,包括存在的和已经删除的文件,这些信息包括文件名和inode。然后利用inode信息结合日志去查询该inode所在的block位置,包括直接块、间接块等信息。最后利用dd命令将这些信息备份出来,从而恢复数据文件。

    6.2.2 ext3grep的安装过程

    操作系统环境:CentOS release 5.4。

    ext3grep版本:ext3grep-0.10.1。

    ext3grep官方网站:http://code.google.com/p/grep/,可以从这里下载最新的ext3grep版本。这里下载的是ext3grep-0.10.1.tar.ga。

    所需的系统相关包:

    yum install -y e2fsprogs*

    □[root@localhost~]#rpm-qa|grep e2fsprogs

    □e2fsprogs-libs-1.39-8.el5

    □e2fsprogs-1.39-8.el5

    □e2fsprogs-devel-1.39-8.el5

    系统必须安装e2fsprogs-libs,不然后面ext3grep的安装会出现问题。

    下面进入编译安装阶段,过程如下:

    [root@localhost /opt]# tar zxvf ext3grep-0.10.1.tar.gz

    [root@localhost ext3grep-0.10.1]# ./configure

    [root@localhost ext3grep-0.10.1]# make

    [root@localhost ext3grep-0.10.1]# make install

    [root@localhost ext3grep-0. 10.1]# ext3grep  —v

    Running ext3grep veraion 0. 10.1

    这样,ext3grep就安装完成了,默认的ext3grep命令放在/usr/local/bin目录下。ext3grep的使用非常简单,这里不做介绍,可以通过“ext3grep --help”获取详细的使用帮助。

    6.3通过ext3grep恢复误删除的文件与目录

    6.3.1  数据恢复准则

        当发现某个分区的数据被误删除后,要做的第一件事是立刻卸载被误删除文件所在的分区,或者重新以只读方式挂载此分区。

        这么做的原因其实很简单:删除一个文件,就是将文件inode节点中的扇区指针清除,同时,释放这些数据对应的数据块,而真实的文件还存留在磁盘分区中。但是这些被删除的文件不一定会一直存留在磁盘中,当这些释放的数据块被操作系统重新分配时,那些被删除的数据就会被覆盖。因此,在数据误删除后,马上卸载文件所在分区可以降低数据块中数据盖的风险,进而提高成功恢复数据的机率。

    6.3.2实战ext3grep恢复文件

    1.模拟数据误删除环境

      下面通过一个模拟环境,详细介绍利用ext3grep恢复数据文件的过程。

      [root@localhost/]#mkdir /disk          #建立一个挂截点

      [root@localhost/]#cd /mydata

      [root@localhost mydata] # dd if=/dev/zero of =/mydata/disk lcount=102400

                                                #模拟磁盘分区,创建一个空设备

    102400+0 records in

    102400+0 records out

    52428800 bytes (52 MB) copied,1.20597 seconds.,43.5 MB/s

      [root@localhost mydata]# mkfs . ext3 /mydata/diskl     #将空设备格式化ext3格式

      [root@localhost mydata]# mount -o loop /mydata/diskl /disk #挂载设备到 /diak目录下

      [root@localhost mydata]# cd /disk/

      [root@localhost mydata]# cp /etc/profile /diek    # 复制文件到模拟磁盘分区

    [root@localhost mydata]# cp /boot/initrd-2.6.18-164.11.1.e15xen.img /disk

    [root@localhost mydata]# echo"ext3grep   test">ext3grep.txt

    [root@localhost mydata]# mkdir /disk/ext3grep

    [root@localhost mydata]# cp /etc/hosts /disk/ext3grep

    [root@localhost mydata]# pwd

    /disk

    [root@localhost mydata]# ls  -al

    总计 2512

    drwxr-xr-x  4  root  root   4096  04-07  16 : 46 .

    drwxr-xr-x 31  root  root   4096  04-07  16 : 45 . .

    drwxr-xr-x  2  root  root   4096  04-07  16 : 46  ext3grep

    -rw-r--r--   1  root  root     14  04 -07  16 : 31  ext3grep . txt

    -rw-------   1  root  root 2535991  04 -07  16 : 30 initrd-2.6.18-164.11.1. e15xen. img

    drwx------  1  root  root   4096  04-07  16 :33  lost+found

    -rw-r--r--   1  root  root   1029  04-07   16:30 profile

    [root@localhost disk] # md5sum  profile     #获取文件校验

    a6e82d979bb95919082d9aceddf56c39 profile

    [root@localhost disk] # md5sum  initrd-2.6.18-164.11.1.el5xen.img

    031226080e00d7f312blf 95454e5alff  initrd-2.6.18-164.11.1.el5xen . img

    [root@localhost disk] # md5sum  ext3grep . txt

    5afe55495cdb666daad667elcd797dcb  ext3grep . txt

    [root@localhost disk] # rm-rf  /disk/*    #模拟误删除数据操作

    [root@localhost disk] # ls

    2.卸载磁盘分区

    执行以下命令卸载磁盘分区:

    [root@localhost disk]# cd /opt            #切换到/opt目录下

    [root@localhost disk]# umount  /disk     #卸载模拟磁盘分区

    3.查询恢复数据信息

    执行如下命令,查询需要恢复的数据信息:

     
       

    [root@localhost /opt] # ext3grep  /mydata/diskl   --ls  -inode 2

    执行该命令后,ext3grep就开始搜索可以恢复的数据文件信息,输出如图6-1所示。

    图6-1  通过ext3grcp查询可恢复的数据信息

    “ext3grep /mydata/diskl  --ls -inode 2“主要用于扫描当前文件系统下所有文件的信息,包括存在的和已经删除的文件,其中含有D标识的就是已被删除的文件,如果不记得被删除的文件的名称,可以通过这种方式来获取要恢复的文件的名称。

    通过下面的方式可以获取文件要恢复的路径信息。

    [root@localhost  /opt] # ext3grep   /mydata/diakl   -- dump- names

    Running ext3grep version 0.10.1

    Number of groups: 7

    Minimum / maximum journal block:  447/4561

    Loading  journal  descriptors . . . sorting . . . done

    The oldest inode block that is still in the journal, appears to be from 1270629014

        =Wed Apr  7 16:30:14 2010

    Number of descriptors in journal: 63; min / max  sequence  numbers: 2 / 10

    Loading  diskl . ext3grep . stage2  . . .  done

    ext3grep

    ext3grep . txt

    ext3grep/hosts

    initrd-2.6.18-164.11.1.e15xen.img

    lost+found

    profile

    4.恢复单个文件

    如果要恢复被删除的某个文件,通过下面方式即可。

    [root@localhost  /opt]# ext3grep /mydata/diskl --restore-file ext3grep.txt

    Running ext3grep version 0.10.1

    Number of  groups:7

    Minimum/maximum journal block: 447/4561

    Loading  journal descriptors . . . sorting . . . done

      The oldest inode block that is still in the journal, appears to be from 1270629014

        = Wed Apr  7 16:30:14  2010

    Number of descriptors in journal: 63, min/max sequence numbers:2/10

    Wiriting output to directory  RESTORED_FILES/

    Loading  diskl. ext3grep. stage2 . . . done

    Restoring  ext3grep.txt

     由上面的输出可知,被删除的文件ext3grep.txt已经成功恢复。那么恢复的数据放到哪里了呢?在这段操作中,在/opt目录下执行ext3grep命令,恢复的数据文件就存放在/opt/RESTORED—FILES目录下,也就是说ext3grep会在执行恢复命令的当前目录下自动创建一个RESTORED_ FILES目录,这个目录专门用于存放恢复的数据。

      下面是恢复指定目录下的某个文件的操作:

      [root@localhost /opt]# ext3grep /mydata/diskl --restore-file ext3grep/hosts

    Running ext3grep version 0.10.1

    Number  of  groups:  7

    Minimum / maximum journal black: 447 / 4561

    Loading journal descriptors. . . Sorting. . . done

    The oldest inode block that is still in the journal, appears to be from 1270629014

        =Wed Apr  7 16:30:14 2010

    Number of descriptors in journal: 63, min / max sequence numbers: 2 / 10

    Loading  diskl . ext3grep . stage2. . .done

    Restoring ext3grep/hosts

        这里要注意的是,“--restore-file”后面指定的是恢复文件路径,这个路径应该是文件的相对路径,这里的相对路径指的是相对指定设备的路径,比如。设备/mydata/disk1的挂载点是/disk,而ext3grep.txt文件就在/disk目录下,因此直接指定文件名就呵以了。如果要恢复/disk/ext3grep/bosts文件,那么指定的参数应该是“ext3grep/hosts”,也就是上面代码中所指定的形式。

     通过“--restore-inode”参数,只需指定文件对应的inode值即可恢复文件。操作如下(其中inode值为12的是profile文件):

    [root@localhost  RESTORED FILES] # ext3grep /mydata/diskl  --restore-inode  12

    Running ext3grep version 0.10.1

    Number of groups: 7

    Minimum / maximum journal block: 447 / 4561

    Loading journal descriptors. . .sorting. . .done

    The oldeat inode block that ia still in the journal, appears to be from 1270629014

         = Wed Apr  7 16:30:14 2010

    Number of de8criptors in journal: 63, min / max sequence numbers: 2 / 10

    Writing output  to directory RESTORED _FILES/

    Restoring inode . 12

    下画进入RESTORED-FILES目录,验证文件是否成功恢复。

    [root@localhost  /opt] #  cd RESTORED_FILES

    [root@localhoat RESTORED_FILES] #  ls

    ext3grep  ext3grep . txt  inode . 12

    [root@localhost  RESTORED_FILES] # md5sum ext3grep.txt

    5afes5495cdb666daad667elcd797dcb  ext3grep . txt

    [root@localhoat  RESTORED_FILES] #  md5sum  inode . 12

    a6e82d979bb95 919082d9aceddf 56c3 9  inode . 12

     根据校验结果可知,这个校验码与文件被删除之前的校验码完全一致,因此,通过这个方式恢复出来的文件是完整的。

     5.恢复所有已删除数据

     当需要恢复的文件较少时,通过前面介绍的指定文件的方式进行逐个恢复是可行的。但是如果要恢复很多个文件,如1000个以上,还采取逐个指定的方式,效率是非常低下的,此时就要利用ext3grep命令的“--restore-all”参数了。具体操作如下:

    [root@localhost  /opt] # ext3grep /mydata/diskl  --restore-all

    Running ext3grep version 0.10.1

    Number of groups: 7

    Minimum / maximum journal block: 447 / 4561

    Loading journal descriptors. . .sorting. . .done

    The oldeat inode block that ia still in the journal, appears to be from 1270629014

         = Wed Apr  7 16:30:14 2010

    Number of descriptors in journal: 63, min / max sequence numbers: 2 / 10

    Loading  diskl . ext3grep . stage2 . . . done

    Reatoring  ext3grep . txt

    Restoring ext3grep/hosts

    Restoring  initrd-2 . 6 . 18 -164 . 11 . 1 . e15xen . img

    Restoring profile

     [root@localhost /opt] # cd RESTORED_FILES/

     [root@localhost RESTORED_FILES] #  ls  -al

    总计 2512

       drwxr-xr-x  4 root root    4096  04-07  16:46.

       drwxr-xr-x 31 root root    4096  04-07  16:45..

       drwxr-xr.x  2 root root    4096  04-07  16:46  ext3grep

        -rw-r-r-   1 root root       14  04-07  16:31  ext3grep.txt

       -rw------- 1 root  root  2535991   04-07   16: 30 initrd-2.6.18 -164. 11 .1.e15xen.img

       drwx----  2 root  root     4096    04-07  16: 33  lost+found

       -rw-r-r-   1 root  root     1029    04-07  16:30  profile

     根据这个输出可知,“-restore-all”参数将指定存储设备中可以恢复的文件都恢复出来并放到了RESTORED FILES目录中。“--restore-all”参数对恢复大量数据文件是非常有用的。

    6.4  通过ext3grep恢复误删除的MySQL表

    6.4.1  MySQL存储引擎介绍

      MySQL数据库在存储管理方面,有多个存储引擎可以选择,MyISAM是默认的存储引擎,它具有高速存储和检素及全文搜索能力,但不支持事务处理和故障恢复,因此,在误删除一个表后,如果没有备份,那么数据就永远丢失了。另一个常用的存储引擎是InnoDB.它具有对事务的回滚和崩溃恢复能力,但是仅仅限于事务管理方面,在对恢复库或表的误删除操作方面有很大的局限性。

      MySQL采用MyISAM存储引擎时,每张表分别对应3个文件,分别是以MYI为后缀的索引文件、以frm为后缀的结构文件、以MYD为后缀的数据文件。恢复MySQL表的过程,其实就是恢复这3个文件的过程。

    6.4.2模拟MySQL表被误删除的环境

     下面介绍在采用的是MyISAM存储引擎的MySQL中模拟表被误删除后的恢复过程。

     这里设定:MySQL所在的磁盘分区为/dev/sda6,挂载到/data目录下,而MySQL的安装目录为/data/mysql。下面进入实例介绍。

      1.查看MySQL数据库表信息

      首先登录MySQL数据库查看cicro库中相关的表信息,操作如图6-2所示。

      接着查看t_manager表的内容及数据结构,操作如图6-3所示。

      2.模拟误删除操作,删除表t_manager

        mysql>drop table t_manager;

        Query OK,  0 rows affected(0.00  sec)

        mysql>exit

     
       

    图6-2  查询cicro库中所有表

     
       

    图6-3  查看t manager表的内容和结构

    3.停止MySQL数据库,卸载MySQL所在分区

    [root@localhost  mysql] #   . /mysqld  stop

    [root@localhost  /] # umount /dev/sda6

    6.4.3通过ext3grep分析数据、恢复数据

    1.对MySQL执行分区数据扫描

        通过ext3grep分析MySQL数据所在的分区信息,进而判断是否有可恢复的信息,操作

    如图6-4所示。

     
       

    图6-4通过ext3grep查询/data分区可恢复的数据信息

       通过图6-4可知,MySQL目录中有可恢复的数据信息。根据查询到的恢复信息,可知

    MySQL目录的Inode号是34545。接着继续扫描MySQL目录的Inode信息,如图6-5所示。

     
       

    图6-5  扫描MySQL目录F可恢复的数据信息 

        在上面的操作中,首先通过“--Is -inode 2”参数扫描了整个分区信息,查找到MySQL

    目录对应的inode为34545,接着查找inode为34545下面的文件信息。通过对inode为

    34545的MySQL目录进行扫描,查找到了此目录下所有文件和目录的inode信息。根据图

    6-5输出可知,MySQL目录的Directory block为139777,因此,也可以通过下面的命令查

    看MySQL目录下的inode信息。

        [root@localhost  /] #  ext3grep    /dev/sda6    - -ls  --block  139777

        由于MySQL数据文件存放在data目录下,因此可以通过ext3grep继续查看inode为

     
       

    36577,即data目录下的文件信息,过程如图6-6所示。

    图6-6查看Inode为36577目录下的可恢复的数据信息

        mysql表文件存放在cicro目录下,因此,可以继续查看inode为40641的目录信息,过程如图6-7所示。

        到这里为止,根据D标识可以看到被删除的3个文件,这3个文件正是被删除的表t-

    manager对应的文件。

        2.恢复mysql数据文件

        接下来,通过ext3grep的“-restore-inode”参数恢复这3个文件。过程如下:

    [ root@localhoBt   /] #   ext 3grep      /dev/sda6    - restore -inode   4 0650

    Running ext3grep version 010.1

    Number of groups: 63

    Minimum / maximum journal block: 530 / 9271

    Loading  journal  descriptors . . . Sorting. . . Done

    The oldeat inode block that ia still in the journal, appears to be from 1270697526

          =  Thu Apr   8  11:32 :06  2010

    Number of descriptors in journal: 3796; min / max sequence numbers: 2 / 22

    Reatoring inode . 40650

     [root@localhost  /] # ext3grep   /dev/sda6   -reatore-inode 40653

    Running ext3grep version 0.10.1

    Number of groups: 63

    Minimum / maximum journal block: 530 / 9271

    Loading  jaurnal  descriptors . . .sorting . . .  done

    The oldest inode block that is still in the journal, appears to be from 1270697526

          =Thu Apr   8  11:32 :06  2010

    Number of descriptors in journal: 3796;min / max sequence numbers: 2 / 22

    Restoring inode.40653

     [root@localhost  /] #  ext3grep   /dev/sda6  --restore-inode 40655

    Running ext3grep version 0.10.1

    Number of groupa: 63

    Minimum / maximum journal block: 530 / 9271

    Loading journal deacriptors. .. Sorting. . . done

    The oldest inode block that is still in the journal, appears to be fran 1270697526

         = Thu Apr   8  11:32 :06  2010

    Number of deacriptors  in journal: 3796, min / max Bequence numbers: 2 / 22

    Restoring inode. 40655

    图6-7查看Inode为40641目录下的可恢复的数据信息

     
       

        

    接着,查看文件是否已经恢复到了RESTORED FILES目录下。过程如下:

    [root@localhost /] # cd RESTORED_FILES/

    [root@localhost  RESTORED_FILES] #  Is

    Inode . 40650  inOde . 40655 inode . 40653

    可以看到,3个文件已经恢复了。下面将3个文件的名称改为原始名称:

    [roat@localhoat  RESTORED_FILES]#  mv inode . 40650    t_manager. frm

    [roat@localhoat  RESTORED_FILES]#  mv inode . 40653    t_manager.MYD

    [roat@localhoat  RESTORED_FILES]#  mv inode . 40653    t_manager.MYI

    t_manager . f rm   t_manager . MYD      t_manager . MYI

        接着授予这3个文件MySQL用户和组的权限,然后将文件复制到MySQL的数据文件

    目录下。过程如下:

    [root@localhoat RESTORED_FILES] # chown -R mySql:myraql  ./*

    [root@localhost RESTORED_FILES] # cp t_manager.* /data/mysql/data/cicro/

    3.验证已恢复的MySQL表

    下面重新启动MYSQL数据库,验证被删除的数据表是否已经正确恢复,如图6-8所示。

     
       

    图6-8验证恢复的数据表

    可以看到,表t_manager已经被完整地恢复了。

    6.5本章小结

    本章重点讲述了利用ext3grep工具恢复数据文件和MySQL数据库的方法。首先模拟了一个误删除数据文件的环境,然后详细介绍了利用ext3grep工具恢复数据文件的方法,接着

    又通过实例介绍了如何通过ext3grep恢复Mysql数据库下某个表的具体操作过程。其实恢复

    表的过程和恢复文件的过程基本一致,这里介绍的恢复表的方法只是提供了一种思路:当表

    披误删除后,如果没有备份,通过这个方法可以恢复数据以挽回不必要的损失。

        作为一名系统管理人员,每天都要和数据打交道,误删除数据也是难免的,但恢复数据

    不是我们的“本意”,备份数据才是唯一的真理,正所谓:“备份不是万能的,但是没有备份

    是万万不能的”。


    extundelete工具恢复rm -rf 误删除的文件
    --http://www.centoscn.com/CentOS/Intermediate/2015/0114/4489.html

    CentOS有时候执行了 rm -rf 等操作误删了文件绝对是一件可怕的事情,好在有一些解决的办法可以临时救急。
    这时我们就要用到一款叫做extundelete的工具了。

    Linux下执行 rm 并不会真正删除,而是将inode节点中的扇区删除,同时释放数据块。
    在数据块被系统重新分配前,这部分数据还是可以找回来的。

    网上说在删除文件后要立即unmount这个分区,这样做其实是为了让外界不再写入,我们也可以设置为readonly模式代替。
    当然,如果为了不影响其它应用的运行,也可以不做unmount。

    好的,现在就该神器extundelete上场了。以CentOS6.5为例

     

    依赖
    yum -y install e2fsprogs e2fsprogs-libs e2fsprogs-devel
     

    安装
    wget http://jaist.dl.sourceforge.net/project/extundelete/extundelete/0.2.4/extundelete-0.2.4.tar.bz2
    tar jxvf extundelete-0.2.4.tar.bz2
    cd extundelte-0.2.4
    ./configure
    make; make install
     

    查找要恢复的驱动器名
    df
     
    Filesystem             1K-blocks     Used   Available Use% Mounted on
    /dev/sda1                 495844    64150      406094  14% /boot
     

    运行恢复
    默认恢复到当前目录下的RECOVERED_FILES目录中去

     

    恢复单个文件
    extundelete /dev/sdb1 --restore-file hosts
     

    恢复一个目录
    extundelete /dev/sdb1 --restore-files test/
     

    恢复整个分区
    extundelete /dev/sdb1 –-restore-all
    这个工具貌似支持EXT4文件系统,经过实际测试,restore-all比较好用,在初次删除后可以很好的恢复文件及目录结构,
    但是如果我在相同位置新建了相同的文件名或者目录名,就会恢复失败(找不到了)。
    而恢复单独的文件或者目录则没有成功,如果有成功的可以告诉我。








    f

  • 相关阅读:
    React学习笔记(六) Create React App
    React学习笔记(五) 状态提升
    React学习笔记(四) 条件渲染与列表渲染
    React学习笔记(三) 事件处理与表单元素
    React学习笔记(二) 组件
    React学习笔记(一) 入门
    React学习笔记
    Vue学习笔记
    Vue学习笔记(十二) Vue Ajax
    路飞_day2
  • 原文地址:https://www.cnblogs.com/MYSQLZOUQI/p/5252245.html
Copyright © 2020-2023  润新知