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 类在同一类的第二个字段上第二次不起作用