事情是这样的。前几天隔壁部门的哥们对生产环境的数据库执行了drop命令。嗯,一个真实的删库跑路的例子,其实就发生在我身边。还好运维同学很帮忙,后来把数据找回来了。后来听说这哥们虽然没有被辞退,但是也收到了公司的警告。然后,运维端收回了所有环境下数据库的drop命令的权限,甚至包括开发环境。我认为这对我们没有影响。一般情况下,我们不需要删除表。但是过了几天,我在重命名一个表的时候,突然弹出这样一个错误:仔细一看报错:1142-DROPcommanddeniedtouser'hydra'@'localhost'fortable't_orders'这是什么情况,重命名表drop命令还有什么重要的?抱着怀疑的态度,想探究一下没有drop权限对我们日常数据库操作的影响,于是就有了一系列在本地进行的测试。首先,需要一个没有drop权限的mysql用户。我们先在本地环境用root用户登录mysql,取消用户hydra的drop权限。对应grantauthorization命令,可以使用revoke命令取消用户的授权:revokedropon*.*fromhydra@'localhost';好了,准备工作做好了,showtime~在修改表名之前先用navicat修改表如果改名失败,我们再用sql命令试试:上面测试了重命名表的两个命令,没有ALTER也没有RENAME可以正常使用。看来drop的权限确实会影响表名的修改。至于重命名失败的原因,看官方文档的描述:RENAMETABLErenamesoneormoretables。您必须对原始表具有ALTER和DROP权限,对新表具有CREATE和INSERT权限。命名表时,必须对原表有ALTER和DROP权限,对新表有CREATE和INSERT权限。truncate当我需要清空一个表,顺便设置AUTO_INCREMENT的主键为初始值时,突然发现truncate命令无法执行:有了上面的经验,我们来看看官方文档的描述:虽然TRUNCATETABLE类似于DELETE,但它被归类为DDL语句而不是DML语句。它在以下方面与DELETE不同:Truncate操作删除并重新创建表,这比逐行删除行要快得多,特别是对于大型表。Documentation给出的解释是,虽然truncate和delete的功能相似,但是truncate属于DDL语言,而delete属于DML语言。与delete逐行删除数据相比,truncate会删除表,然后创建新表。此操作比删除快得多,尤其是对于大表。从分类上也可以看出两者的区别。DML(datamanipulationlanguage)作为一种数据操作语言,主要对数据进行一些操作,如常用的增、删、改、查等。DDL(DataDefinitionLanguage)是一种数据定义语言,主要用于定义或改变表的结构等操作,并且这个操作过程是隐式提交的,不可回滚。在无法使用truncate的情况下,尝试执行delete:虽然不推荐没有where条件的delete语句,但从功能上来说还是可以执行成功的。再看另外一个问题,表中的自增id是不是reset了?我们知道如果执行了truncate,自增列id的值会被重置为1,我们看一下执行delete后的情况,插入一条数据,查询:从上面的结果可以看到用delete清表后,自增列的值还在原来的基础上自增。如果我们需要重新设置这个值,需要手动对表执行alter命令修改:altertablet_ordersauto_increment=1;dropscope那么,有没有即使没有权限也能成功执行的drop命令呢?我们分别对不同的对象进行测试,首先尝试对数据库、表、视图进行drop操作:dropDATABASEmall;>1044-Accessdeniedforuser'hydra'@'localhost'todatabase'mall'>Time:0.005sdropTABLEt_orders;>1142-DROPcommanddeniedtouser'hydra'@'localhost'fortable't_orders'>Time:0sdropVIEWorder_view;>1142-DROPcommanddeniedtouser'hydra'@'localhost'fortable'order_view'>Time:0.001s以上命令当然没有执行成功,但是尝试使用drop时删除存储过程,意想不到的其他结果出现了。在没有drop权限的情况下,存储过程的drop操作可以执行成功:翻到官方文档中的授权章节,看这张图就明白了:上表说明了,drop命令的作用范围是只是数据库、表和视图,以及存储过程的权限是单独放在alter例程中的,所以即使没有drop权限,我们仍然可以使用drop命令来删除存储过程。删除后如何恢复数据?从前面的实验可以看出,恢复drop权限后虽然不能使用truncate来清空数据表,但是我们仍然可以使用delete语句达到同样的效果,那为什么delete不怕删除的风险数据库??正如我们前面提到的,删除语句属于DDL语言。其实在实际的删除过程中,是逐行删除的,日志中会记录每一行数据的删除日志。下面我们看看如何使用binlog来恢复被删除的数据。首先要求数据库开启binlog,使用如下语句查看是否开启:showvariablelike'%log_bin%';当值为ON时,表示启用了binglog:确保启用了binlog后,我们使用delete删除表Data:deletefromt_orders中的所有条目;在恢复被删除的数据之前,需要先找到数据文件所在的目录:在这个目录下,有几个名为mysql-bin.*****的文件,我们需要根据删除操作的时间来查找出现附近的binglog文件:找到目标binlog文件后,先复制到D:\tmp目录下,然后进入mysql安装目录的bin目录下,执行以下命令:mysqlbinlog--base64-output=decode-rows-v--database=mall--start-datetime="2021-09-1720:50:00"--stop-datetime="2021-09-1721:30:00"D:\tmp\mysql-bin.000001>mysqllog.sql参数说明:base64-output=decode-rows:基于行事件解析成SQL语句,将数据转为普通字符开始读取该时间戳的事件,即开始时间ofdatarecoverystop-datetime:对应上面,是数据恢复的结束时间D:\tmp\mysql-bin.000001:恢复数据的日志文件mysqllog.sql:之后执行恢复数据的输出文件,会在bin目录下生成一个mysqllog.sql文件。打开文件看一下,可以找到删除时执行的delete语句:从语句中可以得到每次执行delete命令时执行的delete语句。一行数据的值,使数据可以恢复。如果要恢复的数据量很大,建议使用脚本批量将delete语句转换为insert语句,以减少恢复数据的工作量。好吧,如果你非要看到这个,答应我,在删除数据库之前,请检查是否启用了binlog?官方文档:https://dev.mysql.com/doc/refman/5.7/en【编辑推荐】HarmonyOS官方战略合作共建-HarmonyOS技术社区苹果推送iOS15正式版更新内容通知抛顶杰牛-图解MySQL8.0优化器查询分析文章三招缓解SQL注入威胁iPhone13即将到来iOS这些硬伤还要熬多久?为什么现在手机越来越贵了?
