MySQL 存储过程在同一连接上的第二次调用失败,“SELECT command denied to user 'user'@'localhost' for table 'view_name'

Posted

技术标签:

【中文标题】MySQL 存储过程在同一连接上的第二次调用失败,“SELECT command denied to user \'user\'@\'localhost\' for table \'view_name\'【英文标题】:MySQL stored procedure fails on second call on same connection with "SELECT command denied to user 'user'@'localhost' for table 'view_name'MySQL 存储过程在同一连接上的第二次调用失败,“SELECT command denied to user 'user'@'localhost' for table 'view_name' 【发布时间】:2011-11-08 22:06:30 【问题描述】:

我有一个名为 sales_observation_daily_summary 的表,它是 sales_observation_daily_summary_view 的物化视图。我已经定义了一个名为 sync_daily_summary_view_with_table 的存储过程,它将刷新物化视图。从功能上讲,它完全符合我的预期。但是,在同一连接上两次调用存储过程时,我遇到了一个奇怪的错误(使用连接池时可能出现的情况)。最初这是在我的 Java 集成测试中出现的,但我能够轻松地在 mysql Workbench 上重现它,因此它不应该与 JDBC 或 Spring 或类似中间的任何东西有关。

call sync_daily_summary_view_with_table();
call sync_daily_summary_view_with_table();

在第一次调用时,它会做它应该做的事情并正常返回。在第二次通话中,我得到:

Error Code: 1142
SELECT command denied to user 'test'@'localhost' for table 'one_pg_someone_sales_observation_daily_summary_view'

one_pg_someone_sales_observation_daily_summary_view 在 sales_observation_daily_summary_view 中被引用,在存储过程中被引用。该错误消息毫无意义,首先,存储过程在第一次运行时没有反对,其次,该用户有足够的权限在该视图上进行选择。

我不会显示所有涉及的视图,因为它非常复杂,但是 sales_observation_daily_summary_view 被定义为其他几个视图的联合:

CREATE ALGORITHM=UNDEFINED DEFINER=`test`@`localhost` 
SQL SECURITY DEFINER 
VIEW `sales_observation_daily_summary_view` AS
        /* Specific Stage and Observer */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   one_pg_someone_sales_observation_daily_summary_view
        UNION ALL /* All Stages */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   all_stages_someone_sales_observation_daily_summary_view
        UNION ALL /* All Activities */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   all_activities_someone_sales_observation_daily_summary_view
        UNION ALL /* All Observers */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   one_pg_everyone_sales_observation_daily_summary_view
        UNION ALL /* Everyone over All Stages */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   all_stages_everyone_sales_observation_daily_summary_view
        UNION ALL /* Everyone over All Activities */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   all_activities_everyone_sales_observation_daily_summary_view
        UNION ALL /* Benchmark */
        SELECT zone,
               session_date,
               session_year,
               session_month,
               session_week,
               phenomenon_group_id,
               phenomenon_group_name,
               stage_id,
               stage_name,
               observer_id,
               series_name,
               benchmark_id,
               session_count,
               session_value,
               benchmark_value
        FROM   benchmark_sales_observation_daily_summary_view

存储过程是这样定义的:

DELIMITER $$

CREATE DEFINER=`test`@`localhost` PROCEDURE `sync_daily_summary_view_with_table`()
BEGIN

                /* Update any values that may have changed */
                UPDATE sales_observation_daily_summary tb, 
                       sales_observation_daily_summary_view vw 
                SET    tb.session_count = vw.session_count, 
                       tb.session_value = vw.session_count, 
                       tb.benchmark_value = vw.benchmark_value,
                       tb.series_name = vw.series_name 
                WHERE  vw.zone = tb.zone 
                       AND vw.session_date = tb.session_date 
                       AND Coalesce(vw.phenomenon_group_id, 0) = 
                           Coalesce(tb.phenomenon_group_id, 0) 
                       AND Coalesce(vw.stage_id, 0) = Coalesce(tb.stage_id, 0) 
                       AND Coalesce(vw.observer_id, 0) = Coalesce(tb.observer_id, 0) 
                       AND Coalesce(vw.benchmark_id, 0) = Coalesce(tb.benchmark_id, 0) 
                       AND ( Coalesce(tb.session_count, -1) <> Coalesce(vw.session_count, -1) 
                              OR Coalesce(tb.session_value, -1) <> 
                                 Coalesce(vw.session_value, -1) 
                              OR Coalesce(tb.benchmark_value, -1) <> 
                                 Coalesce(vw.benchmark_value, -1) 
                              OR tb.series_name <> vw.series_name ); 
END

我在本地开发盒上使用 5.1.56 版登录。更新 1 我还在 Amazon RDS 服务器版本 5.1.57-log 上重现了该错误。

更新 2 如果我将存储过程定义为SQL SECURITY INVOKER 并以root 身份执行它,它就可以正常工作。这不是一个可接受的解决方法,但它可能是某种线索。 (例如,这不是表锁定问题。

更新 3 涉及的表是 InnoDB 表。我不确定这是否是一个线索,但是当我在开头添加一个 Start Transaction 并在最后添加一个 Commit 时,完成的时间要长得多,但在第二次调用时出现了同样的错误。

更新 4 我已经简化了存储过程,但仍然重现了问题。它曾经有一个插入语句,后跟一个更新语句。原来update语句足以重现错误,所以我把上面存储过程中的insert语句去掉了。

【问题讨论】:

你能在另一台服务器上重现它吗? 是的,我已经编辑了我的描述以反映这一点。我本地机器上的 5.1.56 和 Amazon RDS 上的 5.1.57 都有这个问题。 你是唯一一个使用视图/存储过程的人吗?听起来视图中的一张表可能会被锁定。 是的。特别是在我的开发箱上,我可以保证我是唯一一个使用表或视图的人。在存储过程结束时我需要做些什么来显式释放一些锁吗? 【参考方案1】:

这可能是交易问题。尝试在 UPDATE 和 INSERT 语句之后添加 COMMIT。如果您还没有,您可能还想尝试使用 InnoDB。

你应该试试这样的函数,看看你是否得到相同的结果:

DELIMITER $$

CREATE DEFINER=`test`@`localhost` PROCEDURE `sync_daily_summary_view_with_table`()
BEGIN

            /* Update any values that may have changed */
            UPDATE sales_observation_daily_summary tb, 
                   sales_observation_daily_summary_view vw 
            SET    tb.session_count = vw.session_count, 
                   tb.session_value = vw.session_count, 
                   tb.benchmark_value = vw.benchmark_value,
                   tb.series_name = vw.series_name 
            WHERE  vw.zone = tb.zone 
                   AND vw.session_date = tb.session_date 
                   AND Coalesce(vw.phenomenon_group_id, 0) = 
                       Coalesce(tb.phenomenon_group_id, 0) 
                   AND Coalesce(vw.stage_id, 0) = Coalesce(tb.stage_id, 0) 
                   AND Coalesce(vw.observer_id, 0) = Coalesce(tb.observer_id, 0) 
                   AND Coalesce(vw.benchmark_id, 0) = Coalesce(tb.benchmark_id, 0) 
                   AND ( Coalesce(tb.session_count, -1) <> Coalesce(vw.session_count, -1) 
                          OR Coalesce(tb.session_value, -1) <> 
                             Coalesce(vw.session_value, -1) 
                          OR Coalesce(tb.benchmark_value, -1) <> 
                             Coalesce(vw.benchmark_value, -1) 
                          OR tb.series_name <> vw.series_name ); 
            COMMIT;
END

【讨论】:

这些是 InnoDB 表。我不确定这是否是一个线索,但是当我在开头添加一个 Start Transaction 并在最后添加一个 Commit 时,它似乎挂起。它只是跑啊跑啊跑,再也没有回来。 更正,它没有挂起,只是运行时间要长得多。然而,我在第二次执行时遇到了同样的错误。 如果它的运行时间更长,我会认为该函数正在更新大量行。 你是从提示符调用函数,还是在测试时从另一个函数调用?我会放弃开始交易。我的猜测仍然是您以某种方式获得了未提交的嵌套事务。在插入之后调用一次提交,在更新之后调用一次。您也可以仅使用更新部分尝试该功能,然后仅使用插入再次尝试该功能吗?我认为这将有助于缩小出错的范围。 我还想知道在提交对表的更改之前视图是否不会更新。我不知道这是否会导致在不提交数据的情况下从插入到更新的麻烦。【参考方案2】:

自动提交的价值是什么? 选择@@autocommit;

如果值为 0,请尝试在两个调用之间添加提交,因为您可能会以某种方式打开事务 调用 sync_daily_summary_view_with_table(); 犯罪; 调用 sync_daily_summary_view_with_table();

物化表是任何视图的一部分吗?

【讨论】:

自动提交为 '1'。该表还不是任何视图的一部分,尽管我计划在 zone 列上使用非常简单的过滤器创建一些视图。【参考方案3】:

这看起来可能是在一个查询中允许多个语句的问题

this(http://dev.mysql.com/doc/refman/5.0/en/mysql-set-server-option.html) 可能是一个选项:

mysql_set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)

连接时更好:

mysql_real_connect (
    mysql, 
    host_name, 
    user_name, 
    password,
    db_name, 
    port_num, 
    socket_name, 
    CLIENT_MULTI_STATEMENTS)

您还应该看看这里以获得更好的解释: http://dev.mysql.com/doc/refman/5.0/en/c-api-multiple-queries.html

【讨论】:

这不是问题。通过 MySQL Workbench,我定期执行由“;”分隔的多个语句我可以在 Workbench 中重现该问题。此外,我不需要一口气做call sync_daily_summary_view_with_table(); call sync_daily_summary_view_with_table();。我还可以通过执行一次call sync_daily_summary_view_with_table() 来重现该问题,等待它完成,然后在同一连接上再次执行它。每个连接只能工作一次,而不是每个请求一次。【参考方案4】:

我不知道你们是否找到了解决这个问题的方法。我遇到了同样的问题并且能够修复它!

当我试图通过过程在视图中进行选择时,我刚刚遇到的问题。第一次它运行良好,但从第二次开始,它正在为我的用户响应命令拒绝消息。

解决方案是使用“管理员”用户创建视图,对过程进行相同操作(使用“管理员”用户创建视图),然后运行这些进程!

问题是我不知道到底是怎么回事,MySQL 使用另一个用户通过视图进行选择,它不使用您的定义器或登录会话用户,而第二次,这个“内部”用户从视图中拒绝命令。

我希望能帮助你们解决这个问题!

【讨论】:

以上是关于MySQL 存储过程在同一连接上的第二次调用失败,“SELECT command denied to user 'user'@'localhost' for table 'view_name'的主要内容,如果未能解决你的问题,请参考以下文章

我的 CustomDeserializer 类在同一类的第二个字段上第二次不起作用

存储过程不走索引的第二次记录

第二次调用存储过程抛出ORA异常

Asp .Net Core WebApi:异常的第二次http调用

WCF 客户端。客户证书。第一次调用成功,第二次调用失败

为啥我通过 ODBC 调用的存储过程在同一位置失败? [关闭]