5

我有一个名为 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-log 版本。
更新 1 我还在 Amazon RDS 服务器版本 5.1.57-log 上重现了该错误。

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

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

更新 4 我已经简化了存储过程并且仍然重现了这个问题。它曾经有一个插入语句,后跟一个更新语句。事实证明,更新语句足以重现错误,所以我从上面的存储过程中删除了插入语句。

4

4 回答 4

2

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

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

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

于 2011-09-07T19:32:41.163 回答
0

不知道大家有没有找到解决这个问题的办法。我遇到了同样的问题并且能够修复它!

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

解决方案是使用“管理员”用户创建视图,并与过程相同(使用“管理员”用户创建它),使用我运行的那些进程!

问题是我不知道究竟如何,MySQL 使用另一个用户通过视图进行选择,它不使用您的定义器或记录的会话用户,并且第二次,这个“内部”用户被拒绝从视图。

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

于 2014-12-16T20:36:00.093 回答
0

这可能是交易问题。尝试在 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
于 2011-09-06T22:19:26.600 回答
0

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

这(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

于 2011-09-09T10:11:24.570 回答