解决办法
--lock-all-tables,-x
在开始导出之前,提交请求锁定所有数据库中的所有表,以保证数据的一致性。这是一个全局读锁,并且自动关闭 --single-transaction 和 --lock-tables 选项。
--lock-tables
它和 --lock-all-tables 类似,不过是锁定当前导出的数据表,而不是一下子锁定全部库下的表。本选项只适用于 MyISAM 表,如果是 Innodb 表可以用 --single-transaction 选项。
--single-transaction
该选项在导出数据之前提交一个 BEGIN SQL语句,BEGIN 不会阻塞任何应用程序且能保证导出时数据库的一致性状态。它只适用于事务表,例如 InnoDB 和 BDB。本选项和 --lock-tables 选项是互斥的,因为 LOCK TABLES 会使任何挂起的事务隐含提交。要想导出大表的话,应结合使用 --quick 选项。
--quick,-q
该选项在导出大表时很有用,它强制 MySQLdump 从服务器查询取得记录直接输出而不是取得所有记录后将它们缓存到内存中。
2.执行没有幂等性,是不是开启了GTID就可以了? 但是开启GTID会报错,执行不下去,恢复时还是需要禁用。
mysqlbinlog /var/lib/mysql/docker-bin.000001 --start-position=499 --stop-position=3716 | mysql -uroot -p123456 test
mysqlbinlog /var/lib/mysql/docker-bin.000001 --start-position=499 --stop-position=3716 | mysql -uroot -p123456 test
查看是否打开了Binlog 【ON表示已经打开 OFF表示关闭 默认关闭状态】
show variables like ‘%log_bin%’;
开启Binlog 【修改完以后重启服务】
方法1:
找到mysql配置中的my.ini文件,在[mysqld]下面添加如下参数
log_bin=mysql-bin
binlog-format=ROW
Mysql binlog日志有三种格式 【binlog-format参数】
1.Statement:每一条会修改数据的sql都会记录在binlog中
2.Row:不记录sql语句上下文相关信息,仅保存哪条记录被修改
3.Mixedlevel:是以上两种level的混合使用,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种.新版本的MySQL中对row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。
方法2:
SET SQL_LOG_BIN=1 命令开启
SET SQL_LOG_BIN=0 命令关闭
开启以后,重启服务会发现data目录下多了日志文件
show master status; 【查看当前正在写入的binlog文件】
测试表, 测试update 【全部改为赵六,再改为老王,恢复为全部为赵六】
update user set name = ‘赵六’;
update user set name = ‘老王’;
show binlog EVENTS in ‘binlog.000178’ ; 【查询所需要恢复的事件起止的位置】
如果是恢复最后一次修改前数据,则使用记录的倒数第二条日志的结束起止坐标
cmd 切换到MySQL存放mysqlbinlog.exe应用程序的bin目录后,执行以下命令,指定数据恢复起始位置,转换为SQL文件
这里的起止坐标为2536 - 2848
mysqlbinlog --no-defaults “D:\DataBase\MYSQL\mysql-8.0.24-winx64\data\binlog.000178” -d test --skip-gtids --start-position=2536 --stop-position=2848>test.sql
cmd登录MySQL,切换到对应数据库,执行命令指定SQL文件位置恢复数据
mysql -uroot -p123456
use test;
source D:\DataBase\MYSQL\mysql-8.0.24-winx64\bin\test.sql
再次查询表数据
cmd 切换到MySQL存放mysqlbinlog.exe应用程序的bin目录后,执行以下命令,可以将Binlog文件转换为txt文件,方便阅读理解
cmd 切换到MySQL存放mysqlbinlog.exe应用程序的bin目录后,执行以下命令,可以一次性完成数据恢复
mysqlbinlog.exe --no-defaults --start-position=2536 --stop-position=2848 --database=test “D:\DataBase\MYSQL\mysql-8.0.24-winx64\data\binlog.000178” | mysql -u root -p
mysqlbinlog: [ERROR] unknown variable ‘default-character-set=utf8’.
如果遇到这个错误原因是mysqlbinlog这个工具无法识别binlog中的配置中的default-character-set=utf8这个指令
两个方法可以解决这个问题:
一:在MySQL的配置/etc/my.cnf中将default-character-set=utf8 修改为 character-set-server = utf8,需要重启MySQL服务
二:用mysqlbinlog --no-defaults mysql-bin.000004 命令打开
近期项目开发中出现了一次误删的操作,于是在网上查找了mysql的回滚操作,这里记录一下。
简单说下binlog,binlog是mysql中的二进制日志,其记录了数据库发生更改的各种变化。所以通过binlog可以回滚或者恢复失误的操作。
恢复一般使用mysqlbinlog命令,该命令是mysql自带的,使用简单。其运行的本质是将日志记录中的事件再次执行一遍。回滚一般要借助第三方工具binlog2sql,其回滚的本质是解析日志文件生成要回滚的sql,我们拷贝执行该sql即可。
2、创建一个test数据库,准备一张空表t1,包含两个字段id、name,如下:
3、通过如下命令查看是否开启binlog记录功能(如果没开则上网搜一下开启教程,这里不过多介绍):
show variables like 'log_bin';
4、为了便于观察测试,使用如下一系列命令产生一个新的binlog日志文件,使得我们后续的操作都记录在新的binlog中。
flush logs //产生一个新的日志文件
show variables like 'log_bin_basename' //查看日志存储地址
show master status; //查看最新日志文件名称
5、插入三条数据,如下:
6、查看此时的binlog日志记录
show binlog events in 'binlog.000068';
这里可以看到我们的三次插入事件
7、删除一条数据,此时的表数据和binlog如下:
可以看到多了一个delete事件,这里注意下binlog中每个事件都有一个begin和commit,我们后面进行恢复或回滚的时候开始和结束的pos都是取的事件整体的开始点和结束点。比如上面删除事件的开始点其实是1105,结束点则是1316。
8、mysqlbinlog恢复数据
注意这里是恢复数据,不是回滚数据,恢复的本质是将原有的插入语句再执行一遍,而回滚则是回退到删除之前的状态。
mysqlbinlog是mysql自带的命令,一般是在mysql安装目录下的bin目录里。因为我们是恢复数据,所以要找到已经删除语句的对应写入事件,将该事件再重新执行一遍即可。
先通过show binlog events in 'binlog.000068'确认下插入语句的事件位置
可以看到开始位置为815,结束位置为1026,接着用mysqlbinlog命令恢复:
mysqlbinlog --no-defaults ..\data\binlog.000068 --start-position=815 --stop-position=1026 | mysql -uroot -p123456 test
下面来看一下表数据和binlog信息:
可以看到表中数据已经恢复,binlog中也多了一次写入事件。
小结:
mysqlbinlog命令只是用于恢复,不能用于回滚。如果数据进行update操作,则很难通过该命令恢复。所以该命令比较适用一些数据迁移,数据同步的场景。
mysqlbinlog 运行过程中如果出现unknown variable 'default-character-set=utf8mb4'异常,可以再该命令后加--no-defaults参数解决:mysqlbinlog --no-defaults
mysqlbinlog命令的详细用法这里没有介绍,需要的可以上官网或者百度搜索。
9、binlog2sql数据回滚
binlog2sql是一个第三方的工具,其安装过程中调试了很久,为了不让该文章的逻辑变的杂乱,这里我新开了一篇文章讲解(binlog2sql 工具安装使用及问题汇总_Interest1_wyt的博客-CSDN博客),不了解该工具的可以参考下。
binlog2sql回滚的原理是生成要回滚事件对应的sql语句,我们最后只需要拷贝该语句实现即可。这里为了便于观察,我们先清空t1表,然后再重新开启一个binlog记录,开启和查看新binlog命令前面介绍过,这里仅截图展示下:
向t1表再次插入三条数据:
修改最后一条数据的name字段,此时表和binlog的记录情况如下:
通过binlog2sql生成回滚sql:
E:\Program Files\PYTHON3.9.5\lib\site-packages\pymysql\cursors.py:170: Warning: (1366, "Incorrect string value: '\\xD6\\xD0\\xB9\\xFA\\xB1\\xEA...' for column 'VARIABLE_VALUE' at row 1")
result = self._query(query)
UPDATE `test`.`t1` SET `id`=3, `name`='回滚3' WHERE `id`=3 AND `name`='更新' LIMIT 1; #start 1105 end 1312 time 2022-04-16 11:20:00
将回滚语句拷贝出来执行后再观察t1表和binlog日志:
可以看到日志中多了一条更新事件,表中数据也被还原。