MySQL基于ROW格式的数据恢复
大家都知道MySQL Binlog 有三种格式,分别是Statement、Row、Mixd。Statement记录了用户执行的原始SQL,而Row则是记录了行的修改情况,在MySQL 5.6以上的版本默认是Mixd格式,但为了保证复制数据的完整性,建议生产环境都使用Row格式,就前面所说的Row记录的是行数据的修改情况,而不是原始SQL。那么线上或者测试环境误操删除或者更新几条数据后,又想恢复,那怎么办呢?下面演示基于Binlog格式为Row的误操后数据恢复,那么怎么把Binlog解析出来生成反向的原始SQL呢?下面我们一起来学习。
下面我们使用 binlog-rollback.pl 对数据进行恢复演示。(这脚本的作者不知道是谁,Github上也没找到这个脚本,所以无法标明出处),脚本是用Perl语言写的,非常好用的一个脚本,当然你也可以用Shell或者Python脚本来实现,下面是脚本的代码:
#!/usr/lib/perl -w
use strict;
use warnings;
use Class::Struct;
use Getopt::Long qw(:config no_ignore_case); # GetOption
register handler system signals
use sigtrap ‘handler’, &sig_int, ‘normal-signals’;
# catch signal
sub sig_int(){
my (KaTeX parse error: Expected 'EOF', got '#' at position 39: … style="color: #̲800080;">@_</sp…signals.\n";
exit 1;
}
my %opt;
my KaTeX parse error: Expected 'EOF', got '#' at position 35: … style="color: #̲000000;">;
</sp…host = ‘127.0.0.1’;
my KaTeX parse error: Expected 'EOF', got '#' at position 35: … style="color: #̲800000;">3306</…user,KaTeX parse error: Expected 'EOF', got '#' at position 31: … style="color: #̲000000;">);
</s…MYSQL, KaTeX parse error: Expected 'EOF', got '#' at position 41: … style="color: #̲800080;">ROLLBACK_DML);
my $outfile = ‘/dev/null’;
my (%do_dbs,%do_tbs);
# tbname=>tbcol, tbcol: @n=>colname,type
my %tbcol_pos;
my KaTeX parse error: Expected 'EOF', got '#' at position 42: … style="color: #̲000000; font-we…SQLTYPE_IST = ‘INSERT’;
my KaTeX parse error: Expected 'EOF', got '#' at position 42: … style="color: #̲000000; font-we…SQLTYPE_DEL = ‘DELETE’;
my KaTeX parse error: Expected 'EOF', got '#' at position 44: … style="color: #̲000000; font-we…SQLAREA_SET = ‘SET’;
my $PRE_FUNCT = '========================== ';
# =========================================================
基于row模式的binlog,生成DML(insert/update/delete)的rollback语句
通过mysqlbinlog -v 解析binlog生成可读的sql文件
提取需要处理的有效sql
"### "开头的行.如果输入的start-position位于某个event group中间,则会导致"无法识别event"错误
将INSERT/UPDATE/DELETE 的sql反转,并且1个完整sql只能占1行
INSERT: INSERT INTO => DELETE FROM, SET => WHERE
UPDATE: WHERE => SET, SET => WHERE
DELETE: DELETE FROM => INSERT INTO, WHERE => SET
用列名替换位置@{1,2,3}
通过desc table获得列顺序及对应的列名
特殊列类型value做特别处理
逆序
注意:
表结构与现在的表结构必须相同[谨记]
由于row模式是幂等的,并且恢复是一次性,所以只提取sql,不提取BEGIN/COMMIT
只能对INSERT/UPDATE/DELETE进行处理
========================================================
sub main{
</span><span style="color: #008000;">#</span><span style="color: #008000;"> get input option</span>
&<span style="color: #000000;">get_options();</span><span style="color: #008000;">#</span>
&<span style="color: #000000;">init_tbcol();</span><span style="color: #008000;">#
&do_binlog_rollback();
}
&main();
# ----------------------------------------------------------------------------------------
Func : get options and set option flag
----------------------------------------------------------------------------------------
sub get_options{
#Get options info
GetOptions(<span style=“color: #800080;”>%opt,
‘help’, # OUT : print help info
‘f|srcfile=s’, # IN : binlog file
‘o|outfile=s’, # out : output sql file
‘h|host=s’, # IN : host
‘u|user=s’, # IN : user
‘p|password=s’, # IN : password
‘P|port=i’, # IN : port
‘start-datetime=s’, # IN : start datetime
‘stop-datetime=s’, # IN : stop datetime
‘start-position=i’, # IN : start position
‘stop-position=i’, # IN : stop position
‘d|database=s’, # IN : database, split comma
‘T|table=s’, # IN : table, split comma
‘i|ignore’, # IN : ignore binlog check ddl and so on
‘debug’, # IN : print debug information
) or print_usage();
</span><span style="color: #0000ff;">if</span> (!<span style="color: #0000ff;">scalar</span>(<span style="color: #800080;">%opt</span><span style="color: #000000;">)) {</span>&<span style="color: #000000;">print_usage();
}</span><span style="color: #008000;">#</span><span style="color: #008000;"> Handle for options</span>
<span style="color: #0000ff;">if</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">f</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}){</span><span style="color: #800080;">$srcfile</span> = <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">f</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span>&merror(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">please input binlog file</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);
}</span><span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">h</span><span style="color: #000000; font-weight: bold;">'</span>} and <span style="color: #800080;">$host</span> = <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">h</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">u</span><span style="color: #000000; font-weight: bold;">'</span>} and <span style="color: #800080;">$user</span> = <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">u</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">p</span><span style="color: #000000; font-weight: bold;">'</span>} and <span style="color: #800080;">$pwd</span> = <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">p</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">P</span><span style="color: #000000; font-weight: bold;">'</span>} and <span style="color: #800080;">$port</span> = <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">P</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">o</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}) {</span><span style="color: #800080;">$outfile</span> = <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">o</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};</span><span style="color: #008000;">#</span><span style="color: #008000;"> 清空 outfile</span>`echo <span style="color: #000000; font-weight: bold;">''</span> > <span style="color: #800080;">$outfile</span><span style="color: #000000;">`;
}</span><span style="color: #008000;">#</span>
<span style="color: #800080;">$MYSQL</span> = qq{mysql -h<span style="color: #800080;">$host</span> -u<span style="color: #800080;">$user</span> -p<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">$pwd</span><span style="color: #000000; font-weight: bold;">'</span> -P<span style="color: #800080;">$port</span><span style="color: #000000;">};
</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">get_options::MYSQL\n\t$MYSQL</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);</span><span style="color: #008000;">#</span><span style="color: #008000;"> 提取binlog,不需要显示列定义信息,用-v,而不用-vv</span>
<span style="color: #800080;">$MYSQLBINLOG</span> = qq{mysqlbinlog -<span style="color: #000000;">v};
</span><span style="color: #800080;">$MYSQLBINLOG</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> --start-position=</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">start-position</span><span style="color: #000000; font-weight: bold;">'</span>} <span style="color: #0000ff;">if</span> <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">start-position</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$MYSQLBINLOG</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> --stop-position=</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">stop-position</span><span style="color: #000000; font-weight: bold;">'</span>} <span style="color: #0000ff;">if</span> <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">stop-postion</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$MYSQLBINLOG</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> --start-datetime='</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">start-datetime</span><span style="color: #000000; font-weight: bold;">'</span>}.<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">"</span> <span style="color: #0000ff;">if</span> <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">start-datetime</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$MYSQLBINLOG</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> --stop-datetime='$opt{'stop-datetime'}'</span><span style="color: #000000; font-weight: bold;">"</span> <span style="color: #0000ff;">if</span> <span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">stop-datetime</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};
</span><span style="color: #800080;">$MYSQLBINLOG</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> $srcfile</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;
</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">get_options::MYSQLBINLOG\n\t$MYSQLBINLOG</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);</span><span style="color: #008000;">#</span><span style="color: #008000;"> 检查binlog中是否含有 ddl sql: CREATE|ALTER|DROP|RENAME</span>
&check_binlog() <span style="color: #0000ff;">unless</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">i</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">});</span><span style="color: #008000;">#</span><span style="color: #008000;"> 不使用mysqlbinlog过滤,USE dbname;方式可能会漏掉某些sql,所以不在mysqlbinlog过滤
# 指定数据库</span>
<span style="color: #0000ff;">if</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">d</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}){</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">@dbs</span> = <span style="color: #0000ff;">split</span>(/,/,<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">d</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">});</span><span style="color: #0000ff;">foreach</span> <span style="color: #0000ff;">my</span> <span style="color: #800080;">$db</span> (<span style="color: #800080;">@dbs</span><span style="color: #000000;">){</span><span style="color: #800080;">$do_dbs</span>{<span style="color: #800080;">$db</span>}=<span style="color: #800000;">1</span><span style="color: #000000;">;}
}</span><span style="color: #008000;">#</span><span style="color: #008000;"> 指定表</span>
<span style="color: #0000ff;">if</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">T</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}){</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">@tbs</span> = <span style="color: #0000ff;">split</span>(/,/,<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">T</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">});</span><span style="color: #0000ff;">foreach</span> <span style="color: #0000ff;">my</span> <span style="color: #800080;">$tb</span> (<span style="color: #800080;">@tbs</span><span style="color: #000000;">){</span><span style="color: #800080;">$do_tbs</span>{<span style="color: #800080;">$tb</span>}=<span style="color: #800000;">1</span><span style="color: #000000;">;}
}</span><span style="color: #008000;">#</span><span style="color: #008000;"> 提取有效DML SQL</span>
<span style="color: #800080;">$ROLLBACK_DML</span> = <span style="color: #800080;">$MYSQLBINLOG</span>.<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> | grep '^### '</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;
</span><span style="color: #008000;">#</span><span style="color: #008000;"> 去掉注释: '### ' -> ''
# 删除首尾空格</span>
<span style="color: #800080;">$ROLLBACK_DML</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"> | sed 's/###\\s*//g;s/\\s*\$//g'</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;
</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">rollback dml\n\t$ROLLBACK_DML</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);</span><span style="color: #008000;">#</span><span style="color: #008000;"> 检查内容是否为空</span>
<span style="color: #0000ff;">my</span> <span style="color: #800080;">$cmd</span> = <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">$ROLLBACK_DML | wc -l</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;
</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">check contain dml sql\n\t$cmd</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">$size</span> = `<span style="color: #800080;">$cmd</span><span style="color: #000000;">`;
</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$size</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">unless</span> (<span style="color: #800080;">$size</span> ><span style="color: #800000;">0</span><span style="color: #000000;">){</span>&merror(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">binlog DML is empty:$ROLLBACK_DML</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);
};
}
# ----------------------------------------------------------------------------------------
Func : check binlog contain DDL
----------------------------------------------------------------------------------------
sub check_binlog{
&mdebug("KaTeX parse error: Expected 'EOF', got '#' at position 50: … style="color: #̲000000; font-we…cmd = "KaTeX parse error: Expected 'EOF', got '#' at position 40: … style="color: #̲000000; font-we…cmd .= " | grep -E -i ‘^(CREATE|ALTER|DROP|RENAME)’ ";
&mdebug("check binlog has DDL cmd\n\tKaTeX parse error: Expected 'EOF', got '#' at position 31: … style="color: #̲000000; font-we…ddlcnt = <span style="color: #800080;">$cmd</span><span style="color: #000000;">
;
chomp($ddlcnt);
</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">$ddlnum</span> = `<span style="color: #800080;">$cmd</span> | wc -<span style="color: #000000;">l`;
</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$ddlnum</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">$res</span> = <span style="color: #800000;">0</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$ddlnum</span>><span style="color: #800000;">0</span><span style="color: #000000;">){</span><span style="color: #008000;">#</span><span style="color: #008000;"> 在ddl sql前面加上前缀<DDL></span><span style="color: #800080;">$ddlcnt</span> = `echo <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">$ddlcnt</span><span style="color: #000000; font-weight: bold;">'</span> | sed <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">s/^/<DDL>/g</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">`;</span>&merror(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">binlog contain $ddlnum DDL:$MYSQLBINLOG. ddl sql:\n$ddlcnt</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);
}</span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$res</span><span style="color: #000000;">;
}
# ----------------------------------------------------------------------------------------
Func : init all table column order
if input --database --table params, only get set table column order
----------------------------------------------------------------------------------------
sub init_tbcol{
&mdebug("KaTeX parse error: Expected 'EOF', got '#' at position 48: … style="color: #̲000000; font-we…cmd .= "KaTeX parse error: Expected 'EOF', got '#' at position 76: … style="color: #̲000000; font-we…cmd .= " | awk ‘{if ($1 ~ “^UPDATE”) {print $2}else {print $3}}’ | uniq ";
$cmd .= " | awk ‘{if ($1 ~ “^UPDATE”) {print $2}else {print $3}}’ | sort | uniq ";
&mdebug("get table name cmd\n\tKaTeX parse error: Expected 'EOF', got '#' at position 31: … style="color: #̲000000; font-we…cmd | " or die “can’t open file:$cmd\n”;
</span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">my</span> <span style="color: #800080;">$tbname</span> = <ALLTABLE><span style="color: #000000;">){</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$tbname</span><span style="color: #000000;">);</span><span style="color: #008000;">#</span><span style="color: #008000;">if (exists $tbcol_pos{$tbname}){# next;#}</span>&init_one_tbcol(<span style="color: #800080;">$tbname</span>) <span style="color: #0000ff;">unless</span> (&ignore_tb(<span style="color: #800080;">$tbname</span><span style="color: #000000;">));}
</span><span style="color: #0000ff;">close</span> ALLTABLE or <span style="color: #0000ff;">die</span> <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">can't close file:$cmd\n</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #008000;">#</span><span style="color: #008000;"> init tb col</span>
<span style="color: #0000ff;">foreach</span> <span style="color: #0000ff;">my</span> <span style="color: #800080;">$tb</span> (<span style="color: #0000ff;">keys</span> <span style="color: #800080;">%tbcol_pos</span><span style="color: #000000;">){</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">tbname->$tb</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">%colpos</span> = %{<span style="color: #800080;">$tbcol_pos</span>{<span style="color: #800080;">$tb</span><span style="color: #000000;">}};</span><span style="color: #0000ff;">foreach</span> <span style="color: #0000ff;">my</span> <span style="color: #800080;">$pos</span> (<span style="color: #0000ff;">keys</span> <span style="color: #800080;">%colpos</span><span style="color: #000000;">){</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">$col</span> = <span style="color: #800080;">$colpos</span>{<span style="color: #800080;">$pos</span><span style="color: #000000;">};</span><span style="color: #0000ff;">my</span> (<span style="color: #800080;">$cname</span>,<span style="color: #800080;">$ctype</span>) = <span style="color: #0000ff;">split</span>(/<span style="color: #800080;">$SPLITER_COL</span>/, <span style="color: #800080;">$col</span><span style="color: #000000;">);</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">\tpos->$pos,cname->$cname,ctype->$ctype</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);}
}
};
# ----------------------------------------------------------------------------------------
Func : init one table column order
----------------------------------------------------------------------------------------
sub init_one_tbcol{
my KaTeX parse error: Expected 'EOF', got '#' at position 37: … style="color: #̲0000ff;">shift<…PRE_FUNCT init_one_tbcol");
# 获取表结构及列顺序
my KaTeX parse error: Expected 'EOF', got '#' at position 34: … style="color: #̲800080;">MYSQL." --skip-column-names --silent -e ‘desc KaTeX parse error: Expected 'EOF', got '#' at position 35: … style="color: #̲000000; font-we…cmd .= " | awk -F’\t’ ‘{print NR"$SPLITER_COL\"\$1\"
$SPLITER_COL"$2}’";
&mdebug("get table column infor cmd\n\tKaTeX parse error: Expected 'EOF', got '#' at position 31: … style="color: #̲000000; font-we…cmd | " or die “can’t open desc $tbname;”;
</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">%colpos</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">my</span> <span style="color: #800080;">$line</span> = <TBCOL><span style="color: #000000;">){</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$line</span><span style="color: #000000;">);</span><span style="color: #0000ff;">my</span> (<span style="color: #800080;">$pos</span>,<span style="color: #800080;">$col</span>,<span style="color: #800080;">$coltype</span>) = <span style="color: #0000ff;">split</span>(/<span style="color: #800080;">$SPLITER_COL</span>/,<span style="color: #800080;">$line</span><span style="color: #000000;">);</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">linesss=$line\n\t\tpos=$pos\n\t\tcol=$col\n\t\ttype=$coltype</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);</span><span style="color: #800080;">$colpos</span>{<span style="color: #800080;">$pos</span>} = <span style="color: #800080;">$col</span>.<span style="color: #800080;">$SPLITER_COL</span>.<span style="color: #800080;">$coltype</span><span style="color: #000000;">;
}
</span><span style="color: #0000ff;">close</span> TBCOL or <span style="color: #0000ff;">die</span> <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">can't colse desc $tbname</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #800080;">$tbcol_pos</span>{<span style="color: #800080;">$tbname</span>} = \<span style="color: #800080;">%colpos</span><span style="color: #000000;">;
}
# ----------------------------------------------------------------------------------------
Func : rollback sql: INSERT/UPDATE/DELETE
----------------------------------------------------------------------------------------
sub do_binlog_rollback{
my KaTeX parse error: Expected 'EOF', got '#' at position 41: … style="color: #̲000000; font-we…ROLLBACK_DML “;
&mdebug(”$PRE_FUNCT do_binlog_rollback");
</span><span style="color: #008000;">#</span><span style="color: #008000;"> INSERT|UPDATE|DELETE</span>
<span style="color: #0000ff;">my</span> <span style="color: #800080;">$sqltype</span><span style="color: #000000;">;
</span><span style="color: #008000;">#</span><span style="color: #008000;"> WHERE|SET</span>
<span style="color: #0000ff;">my</span> <span style="color: #800080;">$sqlarea</span><span style="color: #000000;">;</span><span style="color: #0000ff;">my</span> (<span style="color: #800080;">$tbname</span>, <span style="color: #800080;">$sqlstr</span>) = (<span style="color: #000000; font-weight: bold;">''</span>, <span style="color: #000000; font-weight: bold;">''</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">my</span> (<span style="color: #800080;">$notignore</span>, <span style="color: #800080;">$isareabegin</span>) = (<span style="color: #800000;">0</span>,<span style="color: #800000;">0</span><span style="color: #000000;">);</span><span style="color: #008000;">#</span><span style="color: #008000;"> output sql file</span>
<span style="color: #0000ff;">open</span> SQLFILE, <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">>> $outfile</span><span style="color: #000000; font-weight: bold;">"</span> or <span style="color: #0000ff;">die</span> <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">Can't open sql file:$outfile</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #008000;">#</span><span style="color: #008000;"> binlog file</span>
<span style="color: #0000ff;">open</span> BINLOG, <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">$binlogfile |</span><span style="color: #000000; font-weight: bold;">"</span> or <span style="color: #0000ff;">die</span> <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">Can't open file: $binlogfile</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">my</span> <span style="color: #800080;">$line</span> = <BINLOG><span style="color: #000000;">){</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$line</span><span style="color: #000000;">);</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$line</span> =~ /^(INSERT|UPDATE|<span style="color: #0000ff;">DELETE</span>)/<span style="color: #000000;">){</span><span style="color: #008000;">#</span><span style="color: #008000;"> export sql</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$sqlstr</span> ne <span style="color: #000000; font-weight: bold;">''</span><span style="color: #000000;">){</span><span style="color: #800080;">$sqlstr</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">;\n</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #0000ff;">print</span> SQLFILE <span style="color: #800080;">$sqlstr</span><span style="color: #000000;">;</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">export sql\n\t</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$sqlstr</span><span style="color: #000000;">);</span><span style="color: #800080;">$sqlstr</span> = <span style="color: #000000; font-weight: bold;">''</span><span style="color: #000000;">;}</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$line</span> =~ /^INSERT/<span style="color: #000000;">){</span><span style="color: #800080;">$sqltype</span> = <span style="color: #800080;">$SQLTYPE_IST</span><span style="color: #000000;">;</span><span style="color: #800080;">$tbname</span> = `echo <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">$line</span><span style="color: #000000; font-weight: bold;">'</span> | awk <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">{print \$3}</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">`;</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$tbname</span><span style="color: #000000;">);</span><span style="color: #800080;">$sqlstr</span> = qq{<span style="color: #0000ff;">DELETE</span> FROM <span style="color: #800080;">$tbname</span><span style="color: #000000;">};}</span><span style="color: #0000ff;">elsif</span> (<span style="color: #800080;">$line</span> =~ /^UPDATE/<span style="color: #000000;">){</span><span style="color: #800080;">$sqltype</span> = <span style="color: #800080;">$SQLTYPE_UPD</span><span style="color: #000000;">;</span><span style="color: #800080;">$tbname</span> = `echo <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">$line</span><span style="color: #000000; font-weight: bold;">'</span> | awk <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">{print \$2}</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">`;</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$tbname</span><span style="color: #000000;">);</span><span style="color: #800080;">$sqlstr</span> = qq{UPDATE <span style="color: #800080;">$tbname</span><span style="color: #000000;">};}</span><span style="color: #0000ff;">elsif</span> (<span style="color: #800080;">$line</span> =~ /^<span style="color: #0000ff;">DELETE</span>/<span style="color: #000000;">){</span><span style="color: #800080;">$sqltype</span> = <span style="color: #800080;">$SQLTYPE_DEL</span><span style="color: #000000;">; </span><span style="color: #800080;">$tbname</span> = `echo <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">$line</span><span style="color: #000000; font-weight: bold;">'</span> | awk <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">{print \$3}</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">`;</span><span style="color: #0000ff;">chomp</span>(<span style="color: #800080;">$tbname</span><span style="color: #000000;">);</span><span style="color: #800080;">$sqlstr</span> = qq{INSERT INTO <span style="color: #800080;">$tbname</span><span style="color: #000000;">};}</span><span style="color: #008000;">#</span><span style="color: #008000;"> check ignore table</span><span style="color: #0000ff;">if</span>(&ignore_tb(<span style="color: #800080;">$tbname</span><span style="color: #000000;">)){</span><span style="color: #800080;">$notignore</span> = <span style="color: #800000;">0</span><span style="color: #000000;">;</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"><BINLOG>#IGNORE#:line:</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$line</span><span style="color: #000000;">);</span><span style="color: #800080;">$sqlstr</span> = <span style="color: #000000; font-weight: bold;">''</span><span style="color: #000000;">;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span><span style="color: #800080;">$notignore</span> = <span style="color: #800000;">1</span><span style="color: #000000;">;</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;"><BINLOG>#DO#:line:</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$line</span><span style="color: #000000;">);}}</span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {</span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$notignore</span><span style="color: #000000;">){</span>&merror(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">can't get tbname</span><span style="color: #000000; font-weight: bold;">"</span>) <span style="color: #0000ff;">unless</span> (<span style="color: #0000ff;">defined</span>(<span style="color: #800080;">$tbname</span><span style="color: #000000;">));</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$line</span> =~ /^WHERE/<span style="color: #000000;">){</span><span style="color: #800080;">$sqlarea</span> = <span style="color: #800080;">$SQLAREA_WHERE</span><span style="color: #000000;">;</span><span style="color: #800080;">$sqlstr</span> .=<span style="color: #000000;"> qq{ SET};</span><span style="color: #800080;">$isareabegin</span> = <span style="color: #800000;">1</span><span style="color: #000000;">;}</span><span style="color: #0000ff;">elsif</span> (<span style="color: #800080;">$line</span> =~ /^SET/<span style="color: #000000;">){</span><span style="color: #800080;">$sqlarea</span> = <span style="color: #800080;">$SQLAREA_SET</span><span style="color: #000000;">;</span><span style="color: #800080;">$sqlstr</span> .=<span style="color: #000000;"> qq{ WHERE};</span><span style="color: #800080;">$isareabegin</span> = <span style="color: #800000;">1</span><span style="color: #000000;">;}</span><span style="color: #0000ff;">elsif</span> (<span style="color: #800080;">$line</span> =~ /^\@/<span style="color: #000000;">){</span><span style="color: #800080;">$sqlstr</span> .= &deal_col_value(<span style="color: #800080;">$tbname</span>, <span style="color: #800080;">$sqltype</span>, <span style="color: #800080;">$sqlarea</span>, <span style="color: #800080;">$isareabegin</span>, <span style="color: #800080;">$line</span><span style="color: #000000;">);</span><span style="color: #800080;">$isareabegin</span> = <span style="color: #800000;">0</span><span style="color: #000000;">;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">::unknown sql:</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$line</span><span style="color: #000000;">);}}}
}
</span><span style="color: #008000;">#</span><span style="color: #008000;"> export last sql</span>
<span style="color: #0000ff;">if</span> (<span style="color: #800080;">$sqlstr</span> ne <span style="color: #000000; font-weight: bold;">''</span><span style="color: #000000;">){</span><span style="color: #800080;">$sqlstr</span> .= <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">;\n</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #0000ff;">print</span> SQLFILE <span style="color: #800080;">$sqlstr</span><span style="color: #000000;">;</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">export sql\n\t</span><span style="color: #000000; font-weight: bold;">"</span>.<span style="color: #800080;">$sqlstr</span><span style="color: #000000;">);
}</span><span style="color: #0000ff;">close</span> BINLOG or <span style="color: #0000ff;">die</span> <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">Can't close binlog file: $binlogfile</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #0000ff;">close</span> SQLFILE or <span style="color: #0000ff;">die</span> <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">Can't close out sql file: $outfile</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;</span><span style="color: #008000;">#</span><span style="color: #008000;"> 逆序
# 1!G: 只有第一行不执行G, 将hold space中的内容append回到pattern space
# h: 将pattern space 拷贝到hold space
# $!d: 除最后一行都删除</span>
<span style="color: #0000ff;">my</span> <span style="color: #800080;">$invert</span> = <span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">sed -i '1!G;h;\$!d' $outfile</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">my</span> <span style="color: #800080;">$res</span> = `<span style="color: #800080;">$invert</span><span style="color: #000000;">`;
</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">inverter order sqlfile :$invert</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);
}
# ----------------------------------------------------------------------------------------
Func : transfer column pos to name
deal column value
&deal_col_value($tbname, $sqltype, $sqlarea, $isareabegin, $line);
----------------------------------------------------------------------------------------
sub deal_col_value($$$$KaTeX parse error: Expected '}', got '#' at position 35: … style="color: #̲0000ff;">my</sp…tbname, KaTeX parse error: Expected 'EOF', got '#' at position 37: … style="color: #̲800080;">sqlarea, KaTeX parse error: Expected 'EOF', got '#' at position 41: … style="color: #̲800080;">line) = @_;
&mdebug(“KaTeX parse error: Expected 'EOF', got '#' at position 52: … style="color: #̲000000; font-we…tbname,type->KaTeX parse error: Expected 'EOF', got '&' at position 14: sqltype,area-&̲gt;sqlarea,areabegin->KaTeX parse error: Expected 'EOF', got '&' at position 18: …areabegin,line-&̲gt;line”);
my @vals = split(/=/, KaTeX parse error: Expected 'EOF', got '#' at position 32: … style="color: #̲000000;">);…pos = substr(KaTeX parse error: Expected 'EOF', got '#' at position 33: … style="color: #̲800000;">0</spa…valstartpos = length(KaTeX parse error: Expected 'EOF', got '#' at position 33: … style="color: #̲800000;">2</spa…val = substr(KaTeX parse error: Expected 'EOF', got '#' at position 33: … style="color: #̲800080;">valstartpos);
my %tbcol = %{KaTeX parse error: Expected '}', got '#' at position 38: … style="color: #̲800080;">tbname}};
my (KaTeX parse error: Expected 'EOF', got '#' at position 34: … style="color: #̲800080;">ctype) = split(/KaTeX parse error: Expected 'EOF', got '#' at position 41: … style="color: #̲800080;">tbcol{$pos});
&merror(“can’t get $tbname column KaTeX parse error: Expected 'EOF', got '#' at position 38: … style="color: #̲000000; font-we…cname) || defined(KaTeX parse error: Expected 'EOF', got '#' at position 33: … style="color: #̲000000;">));…cname,type->$ctype”);
</span><span style="color: #008000;">#</span><span style="color: #008000;"> join str</span>
<span style="color: #0000ff;">my</span> <span style="color: #800080;">$joinstr</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$isareabegin</span><span style="color: #000000;">){</span><span style="color: #800080;">$joinstr</span> = <span style="color: #000000; font-weight: bold;">'</span> <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">;
}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span><span style="color: #008000;">#</span><span style="color: #008000;"> WHERE 被替换为 SET, 使用 , 连接</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$sqlarea</span> eq <span style="color: #800080;">$SQLAREA_WHERE</span><span style="color: #000000;">){</span><span style="color: #800080;">$joinstr</span> = <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">, </span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">;</span><span style="color: #008000;">#</span><span style="color: #008000;"> SET 被替换为 WHERE 使用 AND 连接</span>}<span style="color: #0000ff;">elsif</span> (<span style="color: #800080;">$sqlarea</span> eq <span style="color: #800080;">$SQLAREA_SET</span><span style="color: #000000;">){</span><span style="color: #800080;">$joinstr</span> = <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;"> AND </span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span>&merror(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">!!!!!!The scripts error</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);}
}</span><span style="color: #008000;">#</span>
<span style="color: #0000ff;">my</span> <span style="color: #800080;">$newline</span> = <span style="color: #800080;">$joinstr</span><span style="color: #000000;">;</span><span style="color: #008000;">#</span><span style="color: #008000;"> NULL value</span>
<span style="color: #0000ff;">if</span> ((<span style="color: #800080;">$val</span> eq <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">NULL</span><span style="color: #000000; font-weight: bold;">'</span>) && (<span style="color: #800080;">$sqlarea</span> eq <span style="color: #800080;">$SQLAREA_SET</span><span style="color: #000000;">)){</span><span style="color: #800080;">$newline</span> .= qq{ <span style="color: #800080;">$cname</span><span style="color: #000000;"> IS NULL};
}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span><span style="color: #008000;">#</span><span style="color: #008000;"> timestamp: record seconds</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$ctype</span> eq <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">timestamp</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">){</span><span style="color: #800080;">$newline</span> .= qq{<span style="color: #800080;">$cname</span>=from_unixtime(<span style="color: #800080;">$val</span><span style="color: #000000;">)};</span><span style="color: #008000;">#</span><span style="color: #008000;"> datetime: @n=yyyy-mm-dd hh::ii::ss</span>}<span style="color: #0000ff;">elsif</span> (<span style="color: #800080;">$ctype</span> eq <span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">datetime</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">){</span><span style="color: #800080;">$newline</span> .= qq{<span style="color: #800080;">$cname</span>=<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">$val</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">};}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{</span><span style="color: #800080;">$newline</span> .= qq{<span style="color: #800080;">$cname</span>=<span style="color: #800080;">$val</span><span style="color: #000000;">};}
}
</span>&mdebug(<span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">\told>$line\n\tnew>$newline</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">);</span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$newline</span><span style="color: #000000;">;
}
# ----------------------------------------------------------------------------------------
Func : check is ignore table
params: IN table full name # format:dbname
.tbname
RETURN:
0 not ignore
1 ignore
----------------------------------------------------------------------------------------
sub ignore_tb(KaTeX parse error: Expected '}', got '#' at position 35: … style="color: #̲0000ff;">my</sp…fullname = shift;
# 删除</span> <span style="color: #800080;">$fullname</span> =~ s/
//g;
my (KaTeX parse error: Expected 'EOF', got '#' at position 35: … style="color: #̲800080;">tbname) = split(/./,KaTeX parse error: Expected 'EOF', got '#' at position 36: … style="color: #̲000000;">);…res = 0;
</span><span style="color: #008000;">#</span><span style="color: #008000;"> 指定了数据库</span>
<span style="color: #0000ff;">if</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">d</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}){</span><span style="color: #008000;">#</span><span style="color: #008000;"> 与指定库相同</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$do_dbs</span>{<span style="color: #800080;">$dbname</span><span style="color: #000000;">}){</span><span style="color: #008000;">#</span><span style="color: #008000;"> 指定表</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$opt</span>{<span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">T</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}){</span><span style="color: #008000;">#</span><span style="color: #008000;"> 与指定表不同</span><span style="color: #0000ff;">unless</span> (<span style="color: #800080;">$do_tbs</span>{<span style="color: #800080;">$tbname</span><span style="color: #000000;">}){</span><span style="color: #800080;">$res</span> = <span style="color: #800000;">1</span><span style="color: #000000;">;}}</span><span style="color: #008000;">#</span><span style="color: #008000;"> 与指定库不同</span>}<span style="color: #0000ff;">else</span><span style="color: #000000;">{</span><span style="color: #800080;">$res</span> = <span style="color: #800000;">1</span><span style="color: #000000;">;}
}
</span><span style="color: #008000;">#</span><span style="color: #008000;">&mdebug("Table check ignore:$fullname->$res");</span>
<span style="color: #0000ff;">return</span> <span style="color: #800080;">$res</span><span style="color: #000000;">;
}
# ----------------------------------------------------------------------------------------
Func : print debug msg
----------------------------------------------------------------------------------------
sub mdebug{
my (@msg) = @_;
print “<DEBUG>@msg\n” if ($opt{‘debug’});
}
# ----------------------------------------------------------------------------------------
Func : print error msg and exit
----------------------------------------------------------------------------------------
sub merror{
my (@msg) = @_;
print “<Error>:@msg\n”;
&print_usage();
exit(1);
}
# ----------------------------------------------------------------------------------------
Func : print usage
----------------------------------------------------------------------------------------
sub print_usage{
print <<EOF;
==========================================================================================
Command line options :
–help # OUT : print help info
-f, --srcfile # IN : binlog file. [required]
-o, --outfile # OUT : output sql file. [required]
-h, --host # IN : host. default ‘127.0.0.1’
-u, --user # IN : user. [required]
-p, --password # IN : password. [required]
-P, --port # IN : port. default ‘3306’
–start-datetime # IN : start datetime
–stop-datetime # IN : stop datetime
–start-position # IN : start position
–stop-position # IN : stop position
-d, --database # IN : database, split comma
-T, --table # IN : table, split comma. [required] set -d
-i, --ignore # IN : ignore binlog check contain DDL(CREATE|ALTER|DROP|RENAME)
–debug # IN : print debug information
Sample :
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ -i
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ –debug
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -h ‘192.168.1.2’ -u ‘user’ -p ‘pwd’ -P 3307
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ --start-position=107
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ --start-position=107 --stop-position=10000
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ -d ‘db1,db2’
shell> perl binlog-rollback.pl -f ‘mysql-bin.0000*’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ -d ‘db1,db2’ -T ‘tb1,tb2’
EOF
exit;
}
1;
View Code这脚本含有注释以及使用说明,所以使用起来还是比较简单的,如果你会Perl语言,相信也很容易看懂代码。binlog-rollback.pl的使用参数如下:
[root@localhost mysql3306]# perl binlog-rollback.pl ========================================================================================== Command line options :--help # OUT : print help info -f, --srcfile # IN : binlog file. [required]-o, --outfile # OUT : output sql file. [required]-h, --host # IN : host. default '127.0.0.1'-u, --user # IN : user. [required]-p, --password # IN : password. [required] -P, --port # IN : port. default '3306'--start-datetime # IN : start datetime--stop-datetime # IN : stop datetime--start-position # IN : start position--stop-position # IN : stop position-d, --database # IN : database, split comma-T, --table # IN : table, split comma. [required] set -d-i, --ignore # IN : ignore binlog check contain DDL(CREATE|ALTER|DROP|RENAME)--debug # IN : print debug information
Sample :
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ -i
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ –debug
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -h ‘192.168.1.2’ -u ‘user’ -p ‘pwd’ -P 3307
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ --start-position=107
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ --start-position=107 --stop-position=10000
shell> perl binlog-rollback.pl -f ‘mysql-bin.000001’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ -d ‘db1,db2’
shell> perl binlog-rollback.pl -f ‘mysql-bin.0000*’ -o ‘/tmp/t.sql’ -u ‘user’ -p ‘pwd’ -d ‘db1,db2’ -T ‘tb1,tb2’
==========================================================================================
[root@localhost mysql3306]#
下面主要演示对一个表的增、删、修(Insert/Delete/Update)操作,基于Binlog为Row格式的反向解析。
细心看脚本的朋友都能看到这个脚本需要提供一个连接MySQL的用户,主要是为了获取表结构。下面我们测试一个普通用户并给予SELECT权限即可,默认是host是127.0.0.1,这个可以修改脚本,我这里按脚本默认的:
<Test>[(none)]> GRANT SELECT ON *.* TO 'recovery'@'127.0.0.1' identified by '123456'; Query OK, 0 rows affected (0.08 sec)
<Test>[(none)]> flush privileges;
Query OK, 0 rows affected (0.04 sec)
<Test>[(none)]>
往xuanzhi库的表tb1里插入2行数据,记得binlog格式要为ROW:
<Test>[xuanzhi]> show global variables like 'binlog_format'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | ROW | +---------------+-------+ 1 row in set (0.00 sec)
<Test>[xuanzhi]> insert into xuanzhi.tb1 select 1,‘aa’;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
<Test>[xuanzhi]> insert into xuanzhi.tb1 select 2,‘cc’;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
<Test>[xuanzhi]> select * from xuanzhi.tb1;
+–----±-----+
| id | name |
+–----±-----+
| 1 | aa |
| 2 | cc |
+–----±-----+
2 rows in set (0.00 sec)
<Test>[xuanzhi]>
为了看到运行脚本在不指定库看到的效果,我这里再往test库的user表插入两行数据:
<Test>[xuanzhi]> insert into test.user select 1,'user1',20; Query OK, 1 row affected (0.03 sec) Records: 1 Duplicates: 0 Warnings: 0
<Test>[xuanzhi]> insert into test.user select 2,‘user2’,30;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
<Test>[xuanzhi]>
查看此时的此时处于那个binlog:
<Test>[xuanzhi]> show master status; +----------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +----------------------+----------+--------------+------------------+-------------------+ | localhost-bin.000023 | 936 | | | | +----------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
<Test>[xuanzhi]>
下面运行脚本 binlog-rollback.pl ,不指定任何库和表的情况下,这时表把binlog里所有DML操作都生成反向的SQL(最新的DML会生成在输入文件的最前面):
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. [root@localhost mysql3306]#
我们查看输出的文件:/data/t.sql
[root@localhost mysql3306]# cat /data/t.sql DELETE FROM `test`.`user` WHERE `id`=2 AND `name`='user2' AND `age`=30; DELETE FROM `test`.`user` WHERE `id`=1 AND `name`='user1' AND `age`=20; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=2 AND `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=1 AND `name`='aa';
可以看到,INSERT操作的反向操作就是DELETE,这里把所有库的DML操作都查出来了,在后面会演示找单个库或者表所产生的反向SQL。
下面模拟运维人员、开发人员或者DBA误操删除数据,分别在不同的库删除一条记录:
<Test>[xuanzhi]> delete from xuanzhi.tb1 where id=2; Query OK, 1 row affected (0.06 sec)
<Test>[xuanzhi]> delete from test.user where id=1;
Query OK, 1 row affected (0.00 sec)
<Test>[xuanzhi]>
这个时候发现自己删除错了,需要恢复,刚好这些数据不在最新的备份里,正常的恢复方法有两种:
一、是基于最新的完整备份+binlog进行数据恢复了,这时需要把备份导回去,还要找出Binlog DELETE前的pos位置,再进行binlog恢复,恢复完后再把记录恢复到误操的环境上。如果表很大,这时间要很久。
二、因为Binlog格式为ROW时,记录了行的修改,所以DELETE是可以看到所有列的值的,把binlog解析出来,找到被DELETE的记录,通过各种处理再恢复回去,但binlog不能基于一个库或表级别的解析,只能整个binlog解析再进行操作。
以上的方法都比较消耗时间,当然使用binlog-rollback.pl脚本有点类似第二种方法,但是binlog-rollback.pl可以指定库或表进行反向解析,还可以指定POS点,效率相当更高一些。
下面我们运行 binlog-rollback.pl 脚本,生成删除数据语句的反向SQL:
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. [root@localhost mysql3306]#
再次查看输出文件:
[root@localhost mysql3306]# cat /data/t.sql INSERT INTO `test`.`user` SET `id`=1, `name`='user1', `age`=20; INSERT INTO `xuanzhi`.`tb1` SET `id`=2, `name`='bb'; DELETE FROM `test`.`user` WHERE `id`=2 AND `name`='user2' AND `age`=30; DELETE FROM `test`.`user` WHERE `id`=1 AND `name`='user1' AND `age`=20; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=2 AND `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=1 AND `name`='aa';
[root@localhost mysql3306]#
刚刚DELETE的2条记录已经生成了反向INSERT语句,这样恢复就简单多啦:
INSERT INTO `test`.`user` SET `id`=1, `name`='user1', `age`=20; INSERT INTO `xuanzhi`.`tb1` SET `id`=2, `name`='bb';
下面我们模拟修改数据的时候,误修改了,如下:
<Test>[xuanzhi]> select * from xuanzhi.tb1; +------+------+ | id | name | +------+------+ | 1 | aa | +------+------+ 1 row in set (0.00 sec)
<Test>[xuanzhi]> select * from test.user;
+–----±------±-----+
| id | name | age |
+–----±------±-----+
| 2 | user2 | 30 |
+–----±------±-----+
1 row in set (0.00 sec)
<Test>[xuanzhi]> update xuanzhi.tb1 set name = ‘MySQL’ where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
<Test>[xuanzhi]> update test.user set age = 20 where id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
<Test>[xuanzhi]>
这个时候发现修改错数据了,需要还原,同样可以使用脚本binlog-rollback.pl 进行对所在Binlog的DML生成反向的SQL,进行恢复:
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. [root@localhost mysql3306]#
再查看输出文件:
[root@localhost mysql3306]# cat /data/t.sql UPDATE `test`.`user` SET `id`=2, `name`='user2', `age`=30 WHERE `id`=2 AND `name`='user2' AND `age`=20; UPDATE `xuanzhi`.`tb1` SET `id`=1, `name`='aa' WHERE `id`=1 AND `name`='MySQL'; INSERT INTO `test`.`user` SET `id`=1, `name`='user1', `age`=20; INSERT INTO `xuanzhi`.`tb1` SET `id`=2, `name`='bb'; DELETE FROM `test`.`user` WHERE `id`=2 AND `name`='user2' AND `age`=30; DELETE FROM `test`.`user` WHERE `id`=1 AND `name`='user1' AND `age`=20; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=2 AND `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=1 AND `name`='aa';
[root@localhost mysql3306]#
可以看到生成了反向的UPDATE语句:
UPDATE `test`.`user` SET `id`=2, `name`='user2', `age`=30 WHERE `id`=2 AND `name`='user2' AND `age`=20; UPDATE `xuanzhi`.`tb1` SET `id`=1, `name`='aa' WHERE `id`=1 AND `name`='MySQL';
下面进行指定库的反向解析,参数为(-d)
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' -d 'xuanzhi' mysql: [Warning] Using a password on the command line interface can be insecure. [root@localhost mysql3306]# cat /data/t.sql UPDATE `xuanzhi`.`tb1` SET `id`=1, `name`='aa' WHERE `id`=1 AND `name`='MySQL'; INSERT INTO `xuanzhi`.`tb1` SET `id`=2, `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=2 AND `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=1 AND `name`='aa';
[root@localhost mysql3306]#
可以看到输入的文件只含xuanzhi库的所有DML的反向SQL。
下面进行指定库下某个表的反向解析,参数为:-T (为了看到效果在xuanzhi库下的tb2表删除一些记录):
<Test>[xuanzhi]> select * from tb2; +------+------+ | id | name | +------+------+ | 1 | aa | | 2 | bb | | 3 | cc | +------+------+ 3 rows in set (0.04 sec)
<Test>[xuanzhi]> delete from xuanzhi.tb2 where id <2;
Query OK, 1 row affected (0.02 sec)
<Test>[xuanzhi]>
这个时候应该如果只指定xuanzhi库,那么tb1和tb2的DML操作的反向操作都会记录下来:
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' -d 'xuanzhi' mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. [root@localhost mysql3306]# cat /data/t.sql INSERT INTO `xuanzhi`.`tb2` SET `id`=1, `name`='aa'; UPDATE `xuanzhi`.`tb1` SET `id`=1, `name`='aa' WHERE `id`=1 AND `name`='MySQL'; INSERT INTO `xuanzhi`.`tb1` SET `id`=2, `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=2 AND `name`='bb'; DELETE FROM `xuanzhi`.`tb1` WHERE `id`=1 AND `name`='aa';
[root@localhost mysql3306]#
指定单个表tb2:
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' -d 'xuanzhi' -T 'tb2' mysql: [Warning] Using a password on the command line interface can be insecure. [root@localhost mysql3306]# cat /data/t.sql INSERT INTO `xuanzhi`.`tb2` SET `id`=1, `name`='aa';
[root@localhost mysql3306]#
因为上面删除了一条tb2的数据,所有这个文件就对应生成一条tb2的INSERT记录
下面进行POS点生成反向SQL:(--start-position= --stop-position=)
# at 1557 #160308 4:27:23 server id 1283306 end_log_pos 1632 CRC32 0xb67ef6ba Query thread_id=11 exec_time=0 error_code=0 SET TIMESTAMP=1457382443/*!*/; BEGIN /*!*/; # at 1632 #160308 4:27:23 server id 1283306 end_log_pos 1683 CRC32 0x219a127c Table_map: `test`.`user` mapped to number 74 # at 1683 #160308 4:27:23 server id 1283306 end_log_pos 1749 CRC32 0xf5e0d39e Update_rows: table id 74 flags: STMT_END_F
BINLOG ’
K+TdVhPqlBMAMwAAAJMGAAAAAEoAAAAAAAEABHRlc3QABHVzZXIAAwP+AwL+Hgd8Epoh
K+TdVh/qlBMAQgAAANUGAAAAAEoAAAAAAAEAAgAD///4AgAAAAV1c2VyMh4AAAD4AgAAAAV1c2Vy
MhQAAACe0+D1
'/!/;
### UPDATE test
.user
WHERE
@1=2
@2=‘user2’
@3=30
SET
@1=2
@2=‘user2’
@3=20
at 1749
#160308 4:27:23 server id 1283306 end_log_pos 1780 CRC32 0x1e62cb77 Xid = 101
COMMIT/!/;
at 1780
#160308 4:40:32 server id 1283306 end_log_pos 1855 CRC32 0x04dfe1f0 Query thread_id=11 exec_time=1 error_code=0
SET TIMESTAMP=1457383232/!/;
BEGIN
/!/;
at 1855
#160308 4:40:32 server id 1283306 end_log_pos 1907 CRC32 0x897ae6bd Table_map: xuanzhi
.tb2
mapped to number 70
at 1907
#160308 4:40:32 server id 1283306 end_log_pos 1950 CRC32 0xea61aff0 Delete_rows: table id 70 flags: STMT_END_F
BINLOG ’
QOfdVhPqlBMANAAAAHMHAAAAAEYAAAAAAAEAB3h1YW56aGkAA3RiMgACA/4C/goDveZ6iQ==
QOfdViDqlBMAKwAAAJ4HAAAAAEYAAAAAAAEAAgAC//wBAAAAAmFh8K9h6g==
'/!/;
### DELETE FROM xuanzhi
.tb2
WHERE
@1=1
@2=‘aa’
at 1950
#160308 4:40:32 server id 1283306 end_log_pos 1981 CRC32 0x49e1ce9c Xid = 113
COMMIT/!/;
从上面的binlog可以看到开始的--start-position=1557 结束的--stop-position=1981,这一段binlog里做了UPDATE `test`.`user` ... 和 DELETE FROM `xuanzhi`.`tb2` ... 的操作,那么用binlog-rollback.pl应该会生成一个UPDATE和一个INSERT语句
[root@localhost mysql3306]# perl binlog-rollback.pl -f 'localhost-bin.000023' -o '/data/t.sql' -u 'recovery' -p '123456' --start-position=1557 --stop-position=1981
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@localhost mysql3306]# cat /data/t.sql
INSERT INTO `xuanzhi`.`tb2` SET `id`=1, `name`='aa';
UPDATE `test`.`user` SET `id`=2, `name`='user2', `age`=30 WHERE `id`=2 AND `name`='user2' AND `age`=20;
[root@localhost mysql3306]#
更多的测试,就看同学们了,有测试不当的地方请告诉我,大家一起学习。
总结: 一、感谢那些有分享精神的大神们,让我们学到了更多的东西,但开源的脚本需要多测试。
二、误操的情况,时有发生,所以我们要做好备份,做好一些数据恢复的测试。
三、该脚本在处理比较在的binlog时,会经常出现些小问题
作者:陆炫志 出处:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111 您的支持是对博主最大的鼓励,感谢您的认真阅读。本文版权归作者所有,欢迎转载,但请保留该声明。
|
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- Js中的对象方法
这里有一个对象 var student = {name : zizi,age : 16,hobbly : sleep}; console.log(student) /*{name: "zizi", age: 16, hobbly: "sleep"}age: 16hobbly: "sleep"name: "zizi"__proto__: Object*/对象性进行操作:这么操作是很方便…...
2024/4/15 3:06:58 - 编译原理之初见续集
编译原理之初见续集 编译器的结构编译程序主要分为前端和后端前端:只依赖于源程序,独立于目标机器,生成中间代码后端:依赖于目标机器,与源程序无关,只与中间语言有关,从中间代码生成目标代码可能有些人忘了目标代码是什么? 目标代码主要是机器语言或者是汇编语言晦涩的…...
2024/4/20 8:57:09 - DeepLearing—CV系列(十二)——多类多目标物体的侦测——YOLOv3的Pytorch实现(从零使用自己数据集的侦测)
文章目录一、思路1.1 YOLO对图像缩放算法的实现1.2 做数据集(json/xml解析)1.3 配置文件(anchor box等)1.4 造数据集(Mydataset.py)1.5 搭建网络(model.py)1.6 训练(Train.py)1.7 工具iou,nms(tool.py)1.8 侦测(detector.py)二、总结 代码目录(代码包含大量注释…...
2024/4/24 9:58:55 - go工程的运行
1)设置GOROOT2)设置GOPATH(也就是自己在某个地方新建的工程)3)在工程下新建src文件,完成逻辑编码4)编译生成二进制文件5)发现在src统计目录下生成了bin文件夹,然后执行./ch02 即可运行代码...
2024/4/16 23:30:41 - Ubuntu 18.04安装k8s 集群
实际生产环境集群或单机AllInOne安装推荐参照easzlab/kubeasz项目https://github.com/easzlab/kubeasz注意:该项目的kubernetes_dashboard的服务对外暴露采用的是NodePort方式访问kubernetes_dashboard需要使用firefox浏览器 分块手动安装便于理解和学习环境: 两台装有Ubuntu的…...
2024/4/15 3:06:54 - RabbitMq Queue队列
queue 队列是rabblt做流量肖峰最常用的一个队列了吧? 首先我们要封装个工厂类用于创建连接关闭连接使用public class MqConnect {public static Connection connect() throws IOException, TimeoutException {ConnectionFactory connectionFactory=new ConnectionFactory();…...
2024/4/24 14:42:24 - 解决java项目localhost打不开,而127.0.0.1能打开的问题
解决java项目localhost打不开,而127.0.0.1能打开的问题参考文章: (1)解决java项目localhost打不开,而127.0.0.1能打开的问题 (2)https://www.cnblogs.com/liuxiansheng/p/4223406.html 备忘一下。...
2024/4/24 14:42:24 - 使用Linux的Crontab定时执行PHP脚本的方法
先说说cron,它是一个linux下的定时执行工具。根用户以外的用户可以使用 crontab 工具来配置 cron 任务。所有用户定义的 crontab 都被保存在/var/spool/cron 目录中,并使用创建它们的用户身份来执行。 要以某用户身份创建一个 crontab 项目,登录为该用户,然后键入 crontab -…...
2024/4/24 14:42:22 - python中的GIL锁和互斥锁
Python中的GIL锁 在Python中,可以通过多进程、多线程和多协程来实现多任务。 在多线程的实现过程中,为了避免出现资源竞争问题,可以使用互斥锁来使线程同步(按顺序)执行。 但是,其实Python的CPython(C语言实现的)解释器上有一把GIL锁,也就是说Python的程序是处于一个解释器…...
2024/4/24 14:42:21 - 要学好 C 语言 / C++ ,Makefile 可少不了
一、Makefile 简介 1. Makefile 是什么? Makefile 通常指的是一个含有一系列命令(directive)的,通过 Make 自动化编译工具,帮助 C/C++ 程序实现自动编译目标文件的文件。这个文件的默认命名是 “Makefile”。 2. 为什么要使用 Makefile? Makefile 文件描述了整个工程的编…...
2024/4/24 14:42:22 - 使用BulkProcessor批量插入ES
话不多少,贴上代码类实现2个接口implements Flushable, Closeableprivate BulkProcessor bulkProcessor;/*** 初始化静态配置*/@PostConstructpublic void init() {bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() {@Overridepublic void before…...
2024/4/24 14:42:22 - tensorflow转caffemodel之环境和权限问题
在pycharm中直接运行tf113tocaffe.py报错如下: cudnn_conv_layer.cpp:52] Check failed: error == cudaSuccess (30 vs. 0) unknown error 如下图所示:解决方法: 在tf113tocaffe.py所在目录下,打开终端: sudo python3 tf113tocaffe.py (重点是sudo python3)问题2: …...
2024/4/24 14:42:19 - 【XBEE手册】AT命令
【XBEE手册】AT命令 寻址命令 DH(Destination address High ) DL(Destination address Low) MY(16-bit Network Address) MP(16-bit Parent Address) NC(Number of remaining Children) SH(Serial Number High) SL(Serial Number Low) NI(Node Identifier) SE(…...
2024/4/24 14:42:17 - flutter 学习(一)Image 组件
Image.asset 加载本地图片的时候如下: Image.asset("assets/images/sakura.jpg",width: width,fit: BoxFit.fitHeight,),图片的目录应该在pubspec.yaml 文件中 设置assets:- assets/images/如果是这种的需要在文件中声明 assets:- images/logo.png- images/2.0x/log…...
2024/4/23 14:58:18 - 前端性能优化(包含js、css性能优化--笔记)
1、前端优化js和css优化相同、重复的部分放到此处。1、script标签放在body标签尾部,css link标签引用放在head标签内,减少白屏时间。2、合理使用http缓存,js、css文件资源合并,使用精灵图,图片使用base64编码,懒加载等,减少http请求数。js、css文件压缩,gzip压缩,去除…...
2024/4/24 14:42:15 - 1.3 PHP使用ODBC连接sqlserver进行增删改查遇到的坑,详细记录--by changer
PHP连接sql server会比较麻烦,更改配置文件这一方法我没有细致去了解,我选择是用ODBC数据源进行连接,本文适合有一定基础的人员进行阅读哈。 1.设置ODBC数据源,设置你的远程数据库IP,账号密码,默认数据库,设置数据源名字,并测试连接是否成功。 2.使用PHP查询数据库 <…...
2024/4/24 14:42:15 - 零钱兑换 II
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 示例 1: 输入: amount = 5, coins = [1, 2, 5] 输出: 4 解释: 有四种方式可以凑成总金额: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1 示例 2: 输入: amount = 3, coins =…...
2024/4/24 0:58:26 - Keil 4 和 Keil 5 完美共存的简单方法
遇到的问题 安装Keil 5 后,以前用Keil 4 建立的工程都会默认用Keil 5打开,即使打开方式里选择了用Keil 4 打开也无济于事。 解决方法 这里有个非常简单的方法避免这个问题安装Keil 5 时,将两个软件的目录分开,不要放在一起。进入Keil 5 安装目录 找到 UV4.exe,把UV4改成UV…...
2024/4/24 14:42:13 - float与overflow
float <body><img src="./imgs/doraemon.gif"><div>哆啦A梦(日语:ドラえもん),旧译为机器猫,是藤子F不二雄的漫画作品《哆啦A梦》中登场的猫型机器人,本作的主人公。名字的意思是铜锣(ドラ)卫门(えもん)。哆啦A梦肚子上拥有四次元口袋,…...
2024/4/24 14:42:11 - 持久化、持久层简单介绍
持久化就是将程序数据在持久化状态和瞬时状态间转换的机制。 即把数据保存到可永久保存的存储磁盘中 持久层 完成持久化工作的代码块 > > dao层(数据访问对象) 大多数情况下,数据持久化往往就意味着内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各…...
2024/4/24 14:42:11
最新文章
- uniapp——使用微信地址
<view class"use" click"chooseAddress">使用微信收货地址</view>data() {return {// 默认地址checked: true,// 城市cityValue: [],model: {name: ,mobile: ,address: ,infos: ,is_default: 1,id: 0,},}; },chooseAddress() {uni.chooseAddre…...
2024/4/27 2:59:46 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 关于搭建elk日志平台
我这边是使用docker compose进行的搭建 所以在使用的时候 需要自行提前安装docker以及dockercompose环境 或者从官网下载对应安装包也可以 具体文章看下一章节:【ELK】搭建elk日志平台(使用docker-compose),并接入springboot项目...
2024/4/19 6:33:44 - STM32-GPIO
🤓🤓🤓 122.1 2.22.3 344.14.24.34.44.54.64.74.8 56788.18.299.19.2 STM32 第一个外设 1 对我们来说 和IO口没区别 ST公司非叫GPIO 2 2.1 第二个是超频了 F1 72M 这翻转就36 2.2 有cmos 和ttl两种数据手册里给出整个芯片最低电流为150ma 单…...
2024/4/22 10:11:05 - ChatGPT 赚钱初学者指南(上)
原文:The Beginner’s Guide to Earning Money Online with ChatGPT 译者:飞龙 协议:CC BY-NC-SA 4.0 第一章:理解基础知识 什么是 ChatGPT? 在人工智能与人类对话相遇的数字织锦中,ChatGPT 作为一个突出…...
2024/4/24 16:31:18 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/26 18:09:39 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/26 20:12:18 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/26 23:05:52 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/25 18:39:23 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/25 18:39:22 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/25 18:39:22 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/26 21:56:58 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/25 16:48:44 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/26 16:00:35 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/25 18:39:16 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/26 22:01:59 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/26 23:04:58 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/25 2:10:52 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/25 18:39:00 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/26 19:46:12 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/25 18:38:58 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/25 18:38:57 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57