Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL(8.0.24 Community Server-GPL)不会回滚存储过程中的事务_Mysql - Fatal编程技术网

MySQL(8.0.24 Community Server-GPL)不会回滚存储过程中的事务

MySQL(8.0.24 Community Server-GPL)不会回滚存储过程中的事务,mysql,Mysql,我使用的是MySQL(8.0.24社区服务器-GPL)。当存储过程中出现异常时,MySQL不会回滚。下面是一个演示脚本: 首先运行以下SQL: CREATE TABLE already_exists ( ROW_ID INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY (row_id)) ENGINE=INNODB CHARACTER SET utf8mb4; Query OK, 0 r

我使用的是MySQL(8.0.24社区服务器-GPL)。当存储过程中出现异常时,MySQL不会回滚。下面是一个演示脚本:

首先运行以下SQL:

CREATE TABLE already_exists (
             ROW_ID INT UNSIGNED AUTO_INCREMENT,
             PRIMARY KEY  (row_id))
             ENGINE=INNODB CHARACTER SET utf8mb4;
Query OK, 0 rows affected (0.01 sec)
现在创建此存储过程:

delimiter $$
create procedure test_proc()
begin
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        resignal;
    END;

  start transaction;

    set @sql = concat('create table tbl1 (
        ROW_ID INT UNSIGNED AUTO_INCREMENT,
        PRIMARY KEY  (row_id))
        ENGINE=INNODB CHARACTER SET utf8mb4;'
    );
    prepare stmt from @sql;
    execute stmt;

    set @sql = concat('CREATE TABLE already_exists (
        ROW_ID INT UNSIGNED AUTO_INCREMENT,
        PRIMARY KEY  (row_id))
        ENGINE=INNODB CHARACTER SET utf8mb4;
    ');
    prepare stmt from @sql;
    execute stmt;

  commit;
end $$
delimiter ;
call test_proc();
现在调用存储过程:

delimiter $$
create procedure test_proc()
begin
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        resignal;
    END;

  start transaction;

    set @sql = concat('create table tbl1 (
        ROW_ID INT UNSIGNED AUTO_INCREMENT,
        PRIMARY KEY  (row_id))
        ENGINE=INNODB CHARACTER SET utf8mb4;'
    );
    prepare stmt from @sql;
    execute stmt;

    set @sql = concat('CREATE TABLE already_exists (
        ROW_ID INT UNSIGNED AUTO_INCREMENT,
        PRIMARY KEY  (row_id))
        ENGINE=INNODB CHARACTER SET utf8mb4;
    ');
    prepare stmt from @sql;
    execute stmt;

  commit;
end $$
delimiter ;
call test_proc();
期望值:

由于表
已经存在,因此不应创建表
tbl1

观察到:

我得到这个错误:

mysql> call test_proc();
ERROR 1050 (42S01): Table 'already_exists' already exists
但是MySQL也在系统中创建
tbl1
。这是一个bug还是有人知道我该怎么做才能解决这个问题?

DDL语句会导致错误。过程中的第一条CREATETABLE语句提交事务。您不能在MySQL中回滚DDL语句

您可以使用CREATETABLE IF NOT EXISTS语法,这样,如果其中一个表已经存在,就不会导致错误

或者如果要跳过创建两个表(如果其中一个已经存在),则应首先检查它们是否存在:

SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME IN ('tbl1', 'already_exists');
我会这样写:

DELIMITER !!
CREATE PROCEDURE test_proc()
BEGIN
  DECLARE tbl1 VARCHAR(64);
  DECLARE already_exists VARCHAR(64);

  SELECT TABLE_NAME INTO tbl1 FROM INFORMATION_SCHEMA.TABLES
  WHERE TABLE_NAME='tbl1';

  IF tbl1 IS NULL THEN
    CREATE TABLE tbl1 (
      ROW_ID INT UNSIGNED AUTO_INCREMENT,
      PRIMARY KEY  (row_id)
    ) ENGINE=INNODB CHARACTER SET utf8mb4;
  END IF;

  SELECT TABLE_NAME INTO already_exists FROM INFORMATION_SCHEMA.TABLES
  WHERE TABLE_NAME='already_exists';

  IF already_exists IS NULL THEN
    CREATE TABLE already_exists (
      ROW_ID INT UNSIGNED AUTO_INCREMENT,
      PRIMARY KEY  (row_id)
    ) ENGINE=INNODB CHARACTER SET utf8mb4;
  END IF;

END !!
DELIMITER ;

您不需要使用
PREPARE
/
EXECUTE
来运行创建表,除非您需要使某些列或其他语法成为动态的。但对于您的示例,它可以直接执行,如上图所示。

请在Windows10本地计算机上使用8.0.15版本,因为这是Microsoft在Azure服务上为提供MySQL数据库服务的公司使用的最新稳定版本,就我个人而言,在2021年,我受到了这个bug的影响,已经花了3天时间…3天!!!!解决这个问题。 祝你好运 [查看实际的MySQL错误][1]
[1]: https://bugs.mysql.com/bug.php?id=99940

你读过吗?事务通过执行DDL语句隐式提交。谢谢。我现在看到了这一点:InnoDB中的CREATETABLE语句作为单个事务处理。这意味着用户的回滚不会撤消用户在该事务期间所做的CREATE TABLE语句。也许你想把它作为一个答案,我会接受的。在回答中还要提到我应该做些什么来获得预期的行为。你能扩展你的回答并包括需要编写哪些代码来中止(如果任何表已经存在)吗?我已经编写了一个示例过程。如果你想要不同的逻辑,我会让你来实现。谢谢。顺便说一句,我有你的书!顺便说一句,我们不能在不存在的情况下创建表,而不是在答案中进行所有检查吗?这是我上面的第一个建议。