百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

MySQL导入的时候1127的错误

nanshan 2025-01-05 19:19 10 浏览 0 评论

关注我「程序猿集锦」,获取更多分享。

  • 背景
  • 排查原因
  • 错误提示一的原因
      • definer
      • invoker
    • 错误提示二的原因
      • log_bin_trust_function_creators
  • 解决方案
    • 错误提示一的方案
      • 方案一
      • 方案二
    • 错误提示二的方案
  • 总结

背景

在AWS RDS环境下,使用mysqldump备份了一个MySQL数据库数据库,然后想把它用mysql的命令还原到另外一个数据库下面,结果在还原的过程中遇到的下面的错误提示信息,此时的MySQL实例是没有开启binlog。

ERROR 1227 (42000) at line 1163: Access denied; you need (at least one of) the SUPER privilege(s) for this operation

如果在开启了binlog的情况下,把mysqldump命令备份的SQL文件导入到新的schema下面,则会出现如下的错误提示:

ERROR 1419 (HY000) at line 1163: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

下面研究了一下出现上面两个错误的原因分别是什么。

排查原因

错误提示一的原因

先看第一个错误是什么原因导致的

根据第一个错误提示信息,我找到了导出来的SQL文件的第1163行,发现这一行的代码如下所示,在这一行定义了一个trigger触发器。

DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`app_user`@`10.10.%`*/ /*!50003 trigger SEC_RESOURCE_ROLE_DELETE_TS_NN_UPDATE_TRIGGER before update on SEC_RESOURCE_ROLE
            for each row
            begin
                    if not(NEW.DELETE_TS <=> OLD.DELETE_TS) then
                            set NEW.DELETE_TS_NN = if (NEW.DELETE_TS is null, '1000-01-01 00:00:00.000', NEW.DELETE_TS);
                    end if;
            end */;;
DELIMITER ;

根据错误提示信息,再加上定位到的SQL语句,我猜测是当前我执行导入操作的用户,没有权限吗?

为了验证我的猜测,我把同样的SQL文件,在本地的MySQL数据库中,使用root用户导入了一次,结果成功了。而使用了AWS RDS for MySQL的管理员用户想RDS中导入却失败,确实是这个权限的问题。

我们都知道AWS RDS中的用户是没有root权限的,但是没有想到它的权限是这么低。RDS中权限最大的用户就是这个了,如果这个权限都不够的话,那就没有任何其他用户可以用了。只能继续想办法看下具体是需要什么样的权限才可以执行上面的创建触发器的语句。

我把上面创建触发器的SQL语句,稍做修改,发现把里面的DEFINER选项/*!50017 DEFINER=app_user@10.10.%*/给去掉就可以创建成功。改为如下的语句来执行是OK的:

DELIMITER ;;
/*!50003 CREATE*/ /*!50003 trigger SEC_RESOURCE_ROLE_DELETE_TS_NN_UPDATE_TRIGGER before update on SEC_RESOURCE_ROLE
            for each row
            begin
                    if not(NEW.DELETE_TS <=> OLD.DELETE_TS) then
                            set NEW.DELETE_TS_NN = if (NEW.DELETE_TS is null, '1000-01-01 00:00:00.000', NEW.DELETE_TS);
                    end if;
            end */;;
DELIMITER ;

这说明是definer的语句导致了上面的触发器不能正常在MySQL版本的RDS中执行。

在MySQL中,创建函数、存储过程、视图、事件、触发器的时候,可以为其指定definer属性,但是只能指定执行当前创建函数、存储过程、视图、事件、触发器对象DDL语句的用户才可以,如果要指定为其他用户作为definer,则需要使用超级用户才可以。

definer

这里说明一下definer关键字的作用。

definer关键字的作用是用来指定当前的函数、存储过程、视图、事件、触发器等数据库对象是由哪个用户创建的。这里在指定的时候可以为某一个数据库对象指定其他用户作为definer,但前提是拥有super权限的用户才可以在创建数据库对象的时候指定其他用户作为definer,非super权限的用户,不可以这么做,只能指定它自己作为definer。如果在创建对象的时候没有显示的声明definer,会用当前执行创建对象DDL语句的用户来作为默认的definer

如下是定义了definer的存储过程p1的示例。它使用了SQL SECURITY DEFINER属性,并且指定了defineru3@%这个用户,存储过程里面是对数据库procedure_test下面的表t1counter字段执行加1的一个update操作。也就是说,这个存储过程p1每被调用一次,数据库procedure_test下面的表t1counter字段的值就会被加1

use procedure_test;
delimiter ;;
CREATE DEFINER = 'u3'@'%' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
  UPDATE procedure_test.t1 SET counter = counter + 1;
END;;
delimiter ;

/*上面的存储过程,等价于下面的存储过程*/
use procedure_test;
delimiter ;;
CREATE DEFINER = 'u3'@'%' PROCEDURE p1()
-- SQL SECURITY DEFINER /*可以省略该行,不指定的时候,默认就是使用sql security definer*/
BEGIN
  UPDATE procedure_test.t1 SET counter = counter + 1;
END;;
delimiter ;

对于上面的存储过程p1,不管调用这个存储过程的用户是否对procedure_test数据库下面的表t1是否有select、update的权限(注意:修改一个表,前提是可以查询表中的数据,查询出来后才可以修改,所以不仅仅需要update的权限,还需要select的权限),只要这个用户在procedure_test数据库下面有EXECUTE的权限,这个用户就可以调用procedure_test数据库下面的p1这个存储过程。

它是以definer中指定的用户u3@%来执行这个存储过程中的命令的。如果definer中定义的用户u3@%对存储过程中使用的数据库对象procedure_test.t1没有对应的select、update的权限,那么这个调用存储过程p1的用户在以definer用户u3@%去调用该存储过程的时候,也会失败。

invoker

说道了definer属性,就要提一下invoker属性。

在定义函数、存储过程、视图对象的时候,除了可以指定definer属性之外,还可以为其指定invoker属性。invoker属性的含义是,哪个用户可以调用这个数据库对象。

当前一个对象没有在begin前面显示的声明SQL SECURITY DEFINERSQL SECURITY INVOKER的时候,默认是使用SQL SECURITY DEFINER。当一个对象显示的声明了SQL SECURITY INVOKER则会覆盖definer属性的定义,真正在执行对应的对象的时候,会按照invoker的权限去判断是否可以执行对应的命令。

如下是一个定义了invoker的存储过程p2。这个存储过程,和前面不同的是,这里使用了SQL SECURITY INVOKER属性。

use procedure_test;
delimiter ;;
CREATE DEFINER = 'u3'@'%' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
  UPDATE procedure_test.t1 SET counter = counter + 100;
END;;
delimiter ;

对于上面的存储过程p2,虽然定义的时候指定了defineru3@%,但是由于还指定了SQL SECURITY INVOKER,所以在这个存储过程被调用的时候,会根据invoker的属性去判断是否可以成功调用该存储过程,忽略definer属性的约束。这个存储过程p2是否可以调用成功,取决于调用者是否对数据库procedure_test下面的t1表拥有select、update的权限。不会判断调用者对数据库procedure_test是否有execute权限。

**注意:**触发器、事件这两个对象是没有invoker属性,不能为其指定哪些用户可以调用执行它们,它们的调用执行由MySQL自己决定什么时候调用,最多只能为其指定definer属性,标识是哪个用户创建的触发器、事件。其他的几个像:存储过程、函数、视图是可以为其指定invoker属性的,标识哪个用户可以调用该对象。

错误提示二的原因

接下来我们再看第二个错误是什么原因导致的。

根据错误二的提示信息,我尝试使用root用户在我本地的MySQL中执行导入操作,在开启binlog的情况下,是可以导入成功的。但是如果使用一个非root用户,在本地MySQL开启binlog的情况下, 导入确实会出现下面的错误提示:

ERROR 1419 (HY000) at line 1163: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

错误提示给出了关键的解决方式:那就通过参数log_bin_trust_function_creators的配置可以解决这个问题。

log_bin_trust_function_creators

该参数只有在binlog开启的情况下才会生效,如果binlog没有开启,这个参数不管配置成什么值,都不会生效,不起任何作用。所以,接下来我们讨论的这个参数配置为off或者on的前提是:binlog已经是开启的状态。

参数log_bin_trust_function_creators的取值范围是01,对应着off或者on,其默认值为off。它是用来控制MySQL是否信任函数、存储过程、触发器的创建者所创建的这些数据库对象。

  • off,表示不信任。在创建函数、存储过程、触发器之前,MySQL会验证这些对象是否可以被创建。
  • on,表示信任。在创建函数、存储过程、触发器之前,MySQL不会去验证这些对象是否可以被创建,待创建的对象只要语法上没有问题,就可以创建成功。

那么参数log_bin_trust_function_creators到底是对待创建的数据库对象(function、procedure、trigger)做什么验证呢?

如果待创建的数据库对象,在定义过程中引用了非确定性因素的函数事件,比如在SQL语句中引用了rand()、uuid()、now()等MySQL内置的函数,就认为这个待创建的数据库对象是不安全的。因为每次调用或执行这个数据库对象后,它所产生的结果是不确定的。此时MySQL就认为这个对象是安全的数据库对象。

  • 如果参数log_bin_trust_function_creators=off的时候,MySQL就会对待创建的数据库对象进行上面我们描述的检查和验证。是安全的对象,则可以创建成功,如果是不安全的对象则不能创建成功(拥有超级权限的用户除外,超级权限的用户在log_bin_trust_function_creators=off的情况下,即便是非安全的数据库对象,也可以创建成功)。会抛出一个异常信息如下:
ERROR 1419 (HY000) at line 1163: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
  • 如果参数log_bin_trust_function_creators=on的时候,MySQL就不会对待创建的数据库对象进行安全性的检查,在语法没有错误的前提下,可以直接创建成功。

题外话:为什么说引用rand()、uuid()、now()等不确定结果函数的数据库对象就是不安全的呢?

这要从MySQL数据库binlog和主从复制说起。

我们知道在binlog开启的情况下,我们对数据库中数据的任何变更操作都会被记录在binlog中,从库在同步主库的数据的时候,就是读取主库中binlog的记录,然后再从库在执行一遍,来达到从库数据库和主库数据一致的要求。

但是如果我们调用或执行一些数据库对象的时候,它们引用了MySQL内置的不确定性的函数如uuid()。那么binlog中记录的这个操作的SQL语句在不同的MySQL实例上重放的时候,将会得到不同的结果。

例如一个存储过程中对某个表的某一行进行了修改,其语句为update t set a=uuid() where id = 1;。那么在binlog的记录格式是statement格式的时候,binlog中就会记录这样的一个SQL语句,并不是把调用uuid()之后的得到的数据行修改后的内容记录在binlog中。那么这样的binlog在同步到从库之后,从库重放binlog中的这样的记录时,在从库上执行的update t set a=uuid() where id = 1;这个SQL语句后的结果得到的uuid()的值,和主库上的值是相同的可能性几乎为零。这就导致了从库上面id=1的数据行,和主库上面id=1的数据行的内容不一致,进而可能导致主从同步中断。这就是为什么引用不确定性内置函数的数据库对象被视为不安全的原因。

如果在binlog格式是row格式的情况下,就不会出现上面我们描述这样因为不安全的内置函数引用而导致的主从数据不一致的情况,因为row格式的binlog记录的是id=1这一行数据修改后的数据内容,这样的binlog在从库中重放的时候,就直接把修改后的数据内容应用到从库上,而不是把在主库上执行是SQL语句在从库上重新执行一遍。所以,在binlog开启并且格式为row的前提下,即便是把参数log_bin_trust_function_creators=on,表示在创建数据库对象的时候不做验证,也不会导致主从数据不一致的问题。

如果开启了binlog之后并且搭建了主从,同时binlog的格式为statement,参数log_bin_trust_function_creators改为on之后,表示不会对函数、存储过程、触发器等对象在创建的时候,进行验证它们的安全性。就很有可能导致主从数据不一致。

当然,如果没有开启binlog,或者开启了binlog但没有配置主从同步,只是一个单实例的MySQL服务,设置这个参数为on,不会导致主从不同步。但是如果开启了binlog,并且格式为statement,在使用binlog做数据恢复还原的时候,也是有可能导致还原后的数据和原先的数据不一致。所以,只要开启了binlog,格式请一定设置为row格式。

对于binlog开启与否,以及binlog的格式,主从链路的状态和log_bin_trust_function_creators参数之间的影响关系如下:

序号

binlog状态

binlog格式

主从链路状态

log_bin_trust_function_creators状态

对主从或使用binlog恢复数的影响

1

ON

row

ON

ON/OFF都可以

2

ON

row

OFF

ON/OFF都可以

3

ON

mixed

ON

ON/OFF都可以

4

ON

mixed

OFF

ON/OFF都可以

5

ON

statement

ON

ON

6

ON

statement

OFF

ON/OFF都可以

7

OFF

N/A

N/A

ON/OFF都可以

解决方案

错误提示一的方案

了解了definerrevoker的作用之后,根据MySQL给抛出来的错误信息,结合AWS RDS版本的MySQL用户是没有超级用户的权限的,我们就可以理解为什么使用mysqldump导出来的创建触发器的语句会带有definer,并且也能理解为什么导入到新的schema下面就不能导入的原因了。

理解了为什么,我们就可以针对性的进行解决这个问题了。目前的解决方案有以下几种:

方案一

因为AWS RDS版本的MySQL用户没有超级权限,不能指定definer为其他用户,所以我们可以把这个definer定义给删除掉。这样在导入的时候,就会默认使用当前执行导入的用户来作为该触发器的definer

如果你导出来的SQL文件比较小,可以直接双击打开编辑或者使用vi命令来编辑,找到对应的definer定义,将其删除。

如果你导出来的SQL文件比较大,双击打开或者使用vi命令编辑基本不可能,那么就使用如下的sed语句可以将函数、存储过程、视图、事件、触发器中的definer属性给删除掉。在使用sed命令之前,请先备份你的原来的SQL文件,避免删除失败后,不能恢复。

cp your_mysqldump_file.sql your_mysqldump_file.sql.bak

sed -i -e 's/DEFINER=`app_user`@`10.10.\%`//g' your_mysqldump_file.sql

方案二

由于AWS RDS版本的MySQL提供的用户,没有超级权限,所以它不能创建入触发器的时候,指定其他用户作为definer,那么我们可以将dump出来的SQL文件中的definer改为当前RDS提供的用户。同样需要备份源SQL文件,给自己留个后悔药吃。

cp your_mysqldump_file.sql your_mysqldump_file.sql.bak

sed -i -e 's/DEFINER=`app_user`@`10.10.\%`/DEFINER=`your_rds_admin_user`@`\%`/g' your_mysqldump_file.sql

这样修改后的SQL文件,就可以使用RDS提供的用户导入到新的schema下面了。

这里在替换为RDS admin的用户的时候,需要注意,用户名称后面是需要跟上%还是跟上具体的某一个网段,则需要根据你的mysql.user表中定义的RDS admin用户对应的host列中的值是什么。一般情况下面,RDS提供的admin用户他们的网段都是%,而不是具体的某一个网段。

错误提示二的方案

目前我的RDS版本的MySQL是开启了binlog,并且binlog的格式是row格式,但是我没有配置主从同步的链路。所以,我们要修复前面开始遇到的问题,只需要把参数log_bin_trust_function_creators由原先默认的off改为on,来开启信任函数的创建者就可以避免创建触发器、存储过程等数据库对象的验证了。

修改参数的操作如下:

mysql> set global log_bin_trust_function_creators = on;
Query OK, 0 rows affected (0.00 sec)

修改完成上面的参数后,再重新导入SQL文件,即便是里面有触发器、函数的创建,也可以创建成功了。不会对这些将要创建的触发器、函数、存储过程进行安全性的检查了。

但是如果需要这个参数长时间生效,需要在MySQL的参数配置文件中增加这个参数的配置。自己安装部署的MySQL服务,可以修改my.cnf配置文件,如果是RDS版本的MySQL,则需要修改参数组中的这个参数,找到对应的参数,修改后,保存既可以,如果是多个RDS实例,使用同一个参数组,则需要复制出来一份新的参数组来给当前需要修改参数的RDS来使用。为了让新的参数组生效,则需要重启MySQL的RDS服务。

总结

这里简单总结一下这篇文章的内容。

这里,我们主要分析了MySQL中创建函数、存储过程、触发器中时候,定义者definer和调用者invoker的使用规则,它们用来控制MySQL数据库中函数、存储过程、触发器等数据库对象的被调用的时候,哪些用户可以调用它们。

同时,还分析了参数log_bin_trust_function_creators的作用,它用来控制在MySQL中创建函数、存储过程、触发器等数据库对象的时候,是否会对这些待创建的数据库对象进行数据安全性的检查。

关注我「程序猿集锦」,获取更多分享。

相关推荐

雷军1994年写的老代码曝光,被称像诗一样优雅

大数据文摘授权转载自程序员的那些事雷军的代码像诗一样优雅↓↓↓有些网友在评论中质疑,说雷军代码不会是“屎”一样优雅吧。说这话的网友,也许是开玩笑的,也许是真没看过雷军写过的代码。在2011年的时候,我...

原创经验分享:低级bug耗费12小时Fix

调试某程序非常简单的程序,简单到认为不可能存在缺陷,但该BUG处理时间超过12小时:程序属于后台进程,监控系统每隔15秒检查外设IO状态,IO异常后发出报警或复位外设,外设都在linux下有/sys/...

SpringBoot实现的简单停车位管理系统附带导入和演示教程视频

这一次为大家带来的是简单的停车位管理系统,基于SpringBoot+Thymeleaf+Mybatis框架,这个系统相对来说比较简单,很容易学习并快速上手,因为逻辑很清晰,没有太复杂的代码逻辑,所以学...

一个开箱即用的代码生成器(代码自动生成工具开源)

今天给大家推荐一个好用的代码生成器,名为renren-generator,该项目附带前端页面,可以很方便的选择我们所需要生成代码的表。首先我们通过git工具克隆下来代码(地址见文末),导入idea。...

【免费开源】JeecgBoot单点登录源码全部开源了

JeecgBoot单点登录源码全部开源了,有需要的朋友可以来薅羊毛了。一、JeecgBoot介绍JeecgBoot是一款企业级的低代码平台!前后端分离架构SpringBoot2.x,SpringCl...

SpringBoot+JWT+Shiro+Mybatis实现Restful快速开发后端脚手架

作者:lywJee来源:cnblogs.com/lywJ/p/11252064.html一、背景前后端分离已经成为互联网项目开发标准,它会为以后的大型分布式架构打下基础。SpringBoot使编码配置...

为什么越来越多的人选择使用idea软件

IDEA软件是什么?IDEA软件是干什么的?为什么越来越多的人选择使用IDEA软件?IDEA软件,全称IntelliJIDEA,它是由JetBrains公司开发开发的一款功能强大的集成开发环境(ID...

开题报告大学生互助系统(附源码)java毕设

本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容选题背景随着互联网技术的飞速发展,大学生群体对信息共享与互助的需求日益增长。关于大...

SpringBoot项目快速开发框架JeecgBoot——项目简介及系统架构!

项目简介及系统架构JeecgBoot是一款基于SpringBoot的开发平台,它采用前后端分离架构,集成的框架有SpringBoot2.x、SpringCloud、AntDesignof...

新手配电脑13代CPU怎么选择(新手配电脑13代cpu怎么选择好)

Intel第13代酷睿i3、i5、i7、i9系列处理器的核心参数、性能差异及适用群体的详细说明(以桌面端为例):一、13代酷睿全系参数对比(桌面端主流型号)参数i3-13100i5-13600Ki7-...

加速 SpringBoot 应用开发,官方热部署神器真带劲

平时使用SpringBoot开发应用时,修改代码后需要重新启动才能生效。如果你的应用足够大的话,启动可能需要好几分钟。有没有什么办法可以加速启动过程,让我们开发应用代码更高效呢?今天给大家推荐一款Sp...

基于微信小程序的移动端物流系统-计算机毕业设计源码+LW文档

摘要随着Internet的发展,人们的日常生活已经离不开网络。未来人们的生活与工作将变得越来越数字化,网络化和电子化。网上管理,它将是直接管理移动端物流系统app的最新形式。本论文是以构建移动端物流系...

springboot教务管理系统+微信小程序云开发附带源码

今天给大家分享的程序是基于springboot的管理,前端是小程序,系统非常的nice,不管是学习还是毕设都非常的靠谱。本系统主要分为pc端后台管理和微信小程序端,pc端有三个角色:管理员、学生、教师...

SpringBoot全家桶:23篇博客加23个可运行项目让你对它了如指掌

SpringBoot现在已经成为Java开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成。本项目对目前Web开发中常用的各个技术,通过和SpringBoot的集成,并且对各种技术通...

Maven+JSP+Servlet+C3P0+Mysql实现的音乐库管理系统

本系统基于Maven+JSP+Servlet+C3P0+Mysql实现的音乐库管理系统。简单实现了充值、购买歌曲、poi数据导入导出、歌曲上传下载、歌曲播放、用户注册登录注销等功能。难度等级:简单技术...

取消回复欢迎 发表评论: