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