一,首先,我介绍一下脚本的功能。
1,如图,画红线的地方为输入框
2,程序会提示您只能恢复的数据的时间段。 如图 等号线中间的提示
3,提示输入想到恢复的起始时间 如 : 2011-03-10 12:00:00
4,提示输入想到恢复的结束时间 如 : 2011-03-10 13:00:00
5,提示输入想到恢复的库文件,不填此项为全选。要恢复某个库直接填写库名
第一例中我们先不填库名,刚运行结果如上图所示,我们看一下运行后的情况
6,如果不填库名的话,程序运行后,会直接在根目录下生成一个all.sql文件,里面记录里了,起始时间到结束时间的所有数据库的操作,如下图所示
7 恢复数据到数据库
#mysql -p密码
第二例中,我们来一个带库的,我们来看看运行后的结果 (如下图)
1,我们时间选择和上面一个,但是在提示输入库的时候,我们填入 mysql 库。 程序执行成功后会在根目录下生成一个 库名。Sql的文件,些例中,刚在根目录 下生成一个 mysql.sql的文件,我们看看这个文件里有什么 如下图:
里面操作不多,我们来把这个文件导入到数据库里
# mysql -p密码 mysql
导入完成后,就完成了所有的操作了。
那么,接下来,我们来看看这个 datarecover.sh 里到底有什么,还有他是怎么工作的呢?
我先把里面的程序贴出来,看一下,如下
#! /bin/bash
_binlogdir=`cat /etc/my.cnf|grep log-bin|awk -F = '{print $2}'|sed 's/ //g'`
_fristbinlog=`ls -r $_binlogdir* |tail -1`
_lastbinlog=`ls $_binlogdir* |tail -2|grep -v index`
_fristbinlogtime=`stat "$_fristbinlog" |grep Modify|awk -F . '{print $1}'|awk -F Modify: '{print $2}'`
_lastbinlogtime=`stat "$_lastbinlog" |grep Modify|awk -F . '{print $1}'|awk -F Modify: '{print $2}'`
echo "================================================================"
echo " 此程序只能导出 $_fristbinlogtime - $_lastbinlogtime 的sql语句 "
echo "================================================================"
read -p "请输入开始时间 Please enter begian time (such as 2010-01-01 09:23:01) :" fristbegiantime
read -p "请输入结束时间 Please enter over time (such as 2010-10-10 09:23:01) :" fristovertime
read -p "请输入要导出的库,不填此项为全选 :" dbname
_fristNo=`echo $_fristbinlog|awk -F . '{print $2}'`
_lastNo=`echo $_lastbinlog|awk -F . '{print $2}'`
begiantime=`date -d "$fristbegiantime" +%s`
overtime=`date -d "$fristovertime" +%s`
for No in `seq -f %06g $_fristNo $_lastNo`
do
_alltime=`stat $_binlogdir.$No|grep Modify|awk -F . '{print $1}'|awk -F Modify: '{print $2}'`
_alltime=`date -d "$_alltime" +%s`
_begchazhi=$(($begiantime - $_alltime ))
_lachazhi=$(($overtime - $_alltime))
if [ $_begchazhi -gt 0 ]&& [ $_begchazhi -lt 3600 ];then
_begianNo=$No
fi
if [ $_lachazhi -gt 0 ]&& [ $_lachazhi -lt 3600 ];then
_lastNo=$No
fi
done
if [ -z $dbname ];then
for No in `seq -f %06g $_begianNo $_lastNo`
do
mysqlbinlog --start-datetime="$fristbegiantime" --stop-datetime="$fristovertime" $_binlogdir.$No >>/all.sql
done
else
for No in `seq -f %06g $_begianNo $_lastNo`
do
mysqlbinlog --start-datetime="$fristbegiantime" --stop-datetime="$fristovertime" --database $dbname $_binlogdir.$No >>/$dbname.sql
done
fi
代码贴出来了,下面我来解释一下,他是如何工作的,跟往常一下,对每一句代码进行解释(全比较乱,慢慢看)
#! /bin/bash
_binlogdir=`cat /etc/my.cnf|grep log-bin|awk -F = '{print $2}'|sed 's/ //g'`
# 从mysql配置文件里获取 binlog 的存放位置,及binlog的前缀
_fristbinlog=`ls -r $_binlogdir* |tail -1`
#在binlog存放目录里,找出最早时间的binlog文件,并附给_fristbinlog变量
_lastbinlog=`ls $_binlogdir* |tail -2|grep -v index`
#在binlog存放目录里,找出最后时间的binlog文件,并附给_lastbinlog变量
_fristbinlogtime=`stat "$_fristbinlog" |grep Modify|awk -F . '{print $1}'|awk -F Modify: '{print $2}'`
_lastbinlogtime=`stat "$_lastbinlog" |grep Modify|awk -F . '{print $1}'|awk -F Modify: '{print $2}'`
#分别显示出最早的和最晚的binlog文件的时间,分别附给 _fristbinlogtime 和 _lastbinlogtime 变量
echo "================================================================"
echo " 此程序只能导出 $_fristbinlogtime - $_lastbinlogtime 的sql语句 "
echo "================================================================"
#echo 出三条语句,第一个和最后一个好理解,中间一条语句,将最早和最晚的变量打印出来。组成一话语。
read -p "请输入开始时间 Please enter begian time (such as 2010-01-01 09:23:01) :" fristbegiantime
#提示用户输入开始时间,并把开始时间赋值给 fristbegiantime变量
read -p "请输入结束时间 Please enter over time (such as 2010-10-10 09:23:01) :" fristovertime
#提示用户输入结束时间,并把结束时间赋值给 fristovertime 变量
read -p "请输入要导出的库,不填此项为全选 :" dbname
#提示用户输入导出的库,并把值赋给 dbname 变量
_fristNo=`echo $_fristbinlog|awk -F . '{print $2}'
# 获取首个binlog。后面的值 ,(注:binlog格式一般为 binlog.000001 binlog.000002 这一句就是获取 000001 这样的值 )
`
_lastNo=`echo $_lastbinlog|awk -F . '{print $2}'`
#获取最后一个binlog . 后面的值
begiantime=`date -d "$fristbegiantime" +%s`
#将提示输入开始的值 ,变成时间戳格式
overtime=`date -d "$fristovertime" +%s`
#将提示输入结束的值 ,变成时间戳格式
for No in `seq -f %06g $_fristNo $_lastNo`
Do
For循环定义:逐个找出开始时间与结束时间最接近的binlog文件,
_alltime=`stat $_binlogdir.$No|grep Modify|awk -F . '{print $1}'|awk -F Modify: '{print $2}'`
#找出变量 $_binlogdir.$No 的创建时间 $_binlogdir.$No 为遍历所有的binlog文件
_alltime=`date -d "$_alltime" +%s`
#将变量$_binlogdir.$No的时间,变成时间戳格式,
_begchazhi=$(($begiantime - $_alltime ))
#将输入的开始时间的时间戳,减掉遍历出的文件时间戳
_lachazhi=$(($overtime - $_alltime))
#将输入的结束时间的时间戳,减掉遍历出的文件时间戳
if [ $_begchazhi -gt 0 ]&& [ $_begchazhi -lt 3600 ];the
_begianNo=$No
Fi
#如果开始时间的时间戳,减掉遍历出的文件时间戳,大于0 小于3600 则把这个值赋_begianNo 变量,即
$_binlogdir$_begianNo 则是提示输入的时间,开始的文件
if [ $_lachazhi -gt 0 ]&& [ $_lachazhi -lt 3600 ];then
_lastNo=$No
Fi
#如果结束时间的时间戳,减掉遍历出的文件时间戳,大于0 小于3600 则把这个值赋_lastNo 变量 ,即
$_binlogdir$_lastNo 则是提示输入的时间,结束的文件
Done
注:前面文章里提到,binlog文件为每隔一个小时刷新一次。转换为时间戳为 3600
到这里,开始和结束的文件都找到了,我们就要开始从开始到结束的文件里导出数据了
if [ -z $dbname ];then
#我们先判断一开始提示输入的库名,有没有,如果没有的话,我们就直接执行下面的导出所有库操作,有的话,就跳到else后面,执行导出单个库的操作,我们继续往下看。。。
for No in `seq -f %06g $_begianNo $_lastNo`
Do
#这个循环就是导出所有的库,从指定时间开始的文件遍历到指定时间结束的文件,上面的变量要注意,只是 binlog .后面的数定,而不是整个binlog 文件。上面seq 我解释一下: seq -f %06g 这个是seq 打印出的格式,因为binglog .后面都是一个六位数组合,例如000001 000123, 如果不指定 -f %06g的话,就打引出 1 123,前面就没0了,而我们需要保持前面的0.
mysqlbinlog --start-datetime="$fristbegiantime" --stop-datetime="$fristovertime" $_binlogdir.$No >>/all.sql
#每次执行这个导出语句,并把结果追加到/all.sql里面。 --start-datatime 指定开始时间, --stop-datatime指定结束时间。 $_binlogdir.$No 为每个遍历的文件。
done
else
for No in `seq -f %06g $_begianNo $_lastNo`
Do
# 好,这个循环就是导出单个库了,如果定义了单个库的话,那我们就执行这一句,指定开始时间,结束时间,库名,
导出到根目录下以库名。Sql命令的文件
mysqlbinlog --start-datetime="$fristbegiantime" --stop-datetime="$fristovertime" --database $dbname $_binlogdir.$No >>/$dbname.sql
done
Fi
到此就结束了。
总结: 这个脚本功能不大,其实不用这个脚本,就单纯手工操作也很方便,而且这里存在许多bug,比如提示我输入日期时我不写,my.cnf 里面没有定义bin-log ,这都会出现问题,但是跑在我自己的服务器上够了,需要的朋友,可以拷下去,做相应的修改,改成最适合自己的程序。有什么不懂的,可以加我QQ一起讨论:410018348,