我正在尝试在MySQL中执行CREATE PROCEDURE IF NOT EXISTS
。然而,看起来MySQL本身并不支持这一点,这对我来说似乎是一个重大的疏忽。
我创建了一个包含业务模式定义的Spring Batch Java应用程序,其中包括表定义和存储过程定义。表定义很好,因为他们说CREATE TABLE IF NOT EXISTS
。我希望存储过程定义相同,因为这个业务模式脚本将在应用程序启动时运行。
MySQL确实有DROP PROCEDURE IF EXISTS
,但我担心在创建之前运行它会遇到可能的竞争条件。如果我运行了这个应用程序的多个实例,并且其中一个实例在执行DROP和后续CREATE时正在运行其中一个存储过程,该怎么办?这似乎是一个坏主意。我不希望它中断任何已经运行的东西。
其他人现在必须遇到同样的问题。解决方案是什么?
答案 0 :(得分:1)
只需查询 information_schema 中的例程表即可。 示例:强>
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;
答案 1 :(得分:0)
我不建议您依赖应用程序来创建数据库结构。从长期的个人经验来看,它只会引起头痛。 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;
进程返回“true”结果,然后继续使用数据库规范化代码,并在完成时将beingHandledBy
设置为NULL。
编辑:实际上,CONNECTION_ID()可能是一个更好的功能,而不是USER()。如果您有多个实例或线程独立于同一台机器连接,它们将具有相同的USER()值。
答案 2 :(得分:0)
您可以使用以下查询:SHOW PROCEDURE STATUS WHERE NAME ='procedureName' 还可以在这里检查以下答案:found this thread