在尝试在 MySQL 中创建存储过程之前,如何检查它是不是存在?

Posted

技术标签:

【中文标题】在尝试在 MySQL 中创建存储过程之前,如何检查它是不是存在?【英文标题】:How do I check if a stored procedure exists before trying to create it in MySQL?在尝试在 MySQL 中创建存储过程之前,如何检查它是否存在? 【发布时间】:2015-08-11 06:06:56 【问题描述】:

我正在尝试在 mysql 中执行 CREATE PROCEDURE IF NOT EXISTS。但是看起来 MySQL 本身并不支持这一点,这对我来说似乎是一个重大疏忽。

我创建了一个 Spring Batch Java 应用程序,其中包含业务模式定义,其中包括表定义和存储过程定义。表定义很好,因为他们说CREATE TABLE IF NOT EXISTS。我希望存储过程定义相同,因为此业务模式脚本将在应用程序启动时运行。

MySQL 确实有DROP PROCEDURE IF EXISTS,但我担心在创建之前运行它会遇到可能的竞争条件。如果我运行该应用程序的多个实例,而当我执行 DROP 和后续 CREATE 时,其他实例之一正在运行其中一个存储过程,该怎么办?这似乎是一个坏主意。我不希望它打断任何已经在运行的东西。

其他人现在一定遇到过同样的问题。解决办法是什么?

【问题讨论】:

挖,找到这个,引用mysql问题,还在挖codeofhonor.com/blog/… 【参考方案1】:

只需查询 information_schema 中的 routines 表即可。 示例:

select ROUTINE_BODY from routines where ROUTINE_NAME like '%BLA BLA%';

或者可能创建一个函数来查看 proc 是否存在:

use db_where_you_wanna_see_if_proc_exists;
delimiter $$

CREATE FUNCTION PROC_EXISTS(_proc_name VARCHAR(45))
RETURNS BOOLEAN
DETERMINISTIC READS SQL DATA
BEGIN
    DECLARE _exists  TINYINT(1) DEFAULT 0;

    SELECT COUNT(*) INTO _exists
    FROM information_schema.routines 
    WHERE ROUTINE_SCHEMA =  DATABASE()
    AND ROUTINE_NAME =  _proc_name;

    RETURN _exists;

END$$

delimiter ;


SELECT PROC_EXISTS('proc_name') as _exists;

【讨论】:

所以,我已经知道如何选择一些东西来确定程序是否存在,但我遇到的问题是:我如何使用该结果?如何将 CREATE PROCEDURE 调用包装在 MySQL 中的“IF”语句中?【参考方案2】:

您可以使用以下查询:SHOW PROCEDURE STATUS WHERE NAME='procedureName' 还可以在这里查看这些答案:List of Stored Procedures/Functions Mysql Command Line

【讨论】:

【参考方案3】:

我不建议依赖您的应用程序来创建您的数据库结构。从长期的个人经验来看,它只会让人头疼。 CREATE TABLE IF NOT EXISTS 很简单,但最终你需要“ALTER TABLE 如果它不符合我的预期”并且事情开始变得丑陋。也就是说,您可以在information_schema.routines 中找到存储的例程。

我能想到的唯一方法是绕过同时通过此代码运行的多个进程是添加另一个表用作一种锁。 每个应用程序执行UPDATE sentinelTable SET beingHandledBy = user() WHERE beingHandledBy IS NOT NULL;,然后执行SELECT beingHandledBy = user() FROM sentinelTable;,该过程返回“真”结果,然后继续执行数据库规范化代码,完成后将beingHandledBy设置回NULL。

编辑:实际上,CONNECTION_ID() 可能是一个更好的函数,而不是 USER()。如果您有多个实例或线程从同一台机器独立连接,则它们将具有相同的 USER() 值。

【讨论】:

我看到他们在 information_schema.routines;我还看到它们在 mysql.proc 中,但我整个早上都在用头撞我的桌子,试图找出真正能够使用它的语法。似乎我无法在 MySQL 中使用 IF 语句启动查询,所以我不确定如何使用它。 正确的用法是SELECT 1 FROM routines WHERE routine_schema = '[mySchema]' AND routine_name = '[theRoutineName]',并且只有在你得到一个空的结果集时才执行你的创建。这意味着两个查询,而不是一个包含条件的查询。 (但这并不能解决多个应用程序同时通过此代码的问题。)

以上是关于在尝试在 MySQL 中创建存储过程之前,如何检查它是不是存在?的主要内容,如果未能解决你的问题,请参考以下文章

如何在mysql数据库中创建一个包含请求的存储过程

mysql - 在存储过程中创建事件

如何在打开游标之前在存储过程中创建一个临时表?

mysql在存储过程中创建触发器

无法在 phpmyadmin 中创建程序

如何在mysql中创建存储过程