MySQL:过程中的事务

wr98u20j  于 5个月前  发布在  Mysql
关注(0)|答案(5)|浏览(55)

我的程序的基本结构是:

BEGIN
  START TRANSACTION;
    .. Query 1 ..
    .. Query 2 ..
    .. Query 3 ..
  COMMIT;
END;

字符串

**MySQL版本:**5.1.61-0ubuntu0.11.10.1-log

当前,如果“query 2”失败,则提交“query 1”的结果。

  • 如果任何查询失败,我如何回滚事务?
vvppvyoh

vvppvyoh1#

查看http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html
基本上,您声明错误处理程序,它将调用回滚

START TRANSACTION;

DECLARE EXIT HANDLER FOR SQLEXCEPTION 
    BEGIN
        ROLLBACK;
        EXIT PROCEDURE;
    END;
COMMIT;

字符串

wswtfjt7

wswtfjt72#

只是一个替代的代码由rkosegi,

BEGIN

    .. Declare statements ..

    DECLARE EXIT HANDLER FOR SQLEXCEPTION 
    BEGIN
          .. set any flags etc  eg. SET @flag = 0; ..
          ROLLBACK;
    END;

    START TRANSACTION;

        .. Query 1 ..
        .. Query 2 ..
        .. Query 3 ..

    COMMIT;
    .. eg. SET @flag = 1; ..

END

字符串

gcuhipw9

gcuhipw93#

[* 这只是一个解释,其他答案中没有提到 *]
至少在最近的MySQL版本中,你的第一个查询不是提交的。
如果你在同一个会话下查询它,你会看到更改,但是如果你从不同的会话查询它,更改不在那里,它们不是提交的。

怎么回事?

当你打开一个事务,并且其中的一个查询失败时,事务保持打开状态,它不会提交也不会回滚更改。
因此,小心,任何使用以前的查询(如SELECT ... FOR SHARE/UPDATEUPDATEINSERT或任何其他锁定查询)锁定的表/行将保持锁定,直到该会话被杀死(并执行回滚),或者直到下面的查询显式提交它(COMMIT)或implicitly,从而使部分更改永久(这可能在几个小时后发生,而事务处于等待状态)。
这就是为什么解决方案涉及在发生错误时立即向ROLLBACK声明处理程序。

额外

在处理程序内部,您还可以使用RESIGNAL重新引发错误,否则存储过程将执行 “Successfully”

BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION 
        BEGIN
            ROLLBACK;
            RESIGNAL;
        END;

    START TRANSACTION;
        -- .. Query 1 ..
        -- .. Query 2 ..
        -- .. Query 3 ..
    COMMIT;
END;

字符串

zynd9foi

zynd9foi4#

下面是一个在出错时回滚并返回错误代码的事务示例。

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `SP_CREATE_SERVER_USER`(
    IN P_server_id VARCHAR(100),
    IN P_db_user_pw_creds VARCHAR(32),
    IN p_premium_status_name VARCHAR(100),
    IN P_premium_status_limit INT,
    IN P_user_tag VARCHAR(255),
    IN P_first_name VARCHAR(50),
    IN P_last_name VARCHAR(50)
)
BEGIN

    DECLARE errno INT;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
    GET CURRENT DIAGNOSTICS CONDITION 1 errno = MYSQL_ERRNO;
    SELECT errno AS MYSQL_ERROR;
    ROLLBACK;
    END;

    START TRANSACTION;

    INSERT INTO server_users(server_id, db_user_pw_creds, premium_status_name, premium_status_limit)
    VALUES(P_server_id, P_db_user_pw_creds, P_premium_status_name, P_premium_status_limit);

    INSERT INTO client_users(user_id, server_id, user_tag, first_name, last_name, lat, lng)
    VALUES(P_server_id, P_server_id, P_user_tag, P_first_name, P_last_name, 0, 0);

    COMMIT WORK;

END$$
DELIMITER ;

字符串
这是假设自动提交设置为0。希望这有帮助。

vs3odd8k

vs3odd8k5#

您可以在procedure中使用transaction。* 我们不能在function中使用transaction。
例如,创建test表,如下所示:

CREATE TABLE test (
  num int
);

字符串
然后,插入num为2的行,如下所示:

INSERT INTO test (num) VALUES (2);


然后,创建my_proc()过程,将num更新为5,然后通过SIGNAL statement导致错误,然后在事务(START TRANSACTION and COMMIT statements)中使用ROLLBACK statement回滚,如下所示:

DELIMITER $$

CREATE PROCEDURE my_proc() 
BEGIN
  START TRANSACTION;
    UPDATE test SET num = 5;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
    ROLLBACK;
  COMMIT;
END$$ 

DELIMITER ;


然后,调用my_proc()会得到错误,但num不会回滚到2,如下所示:

mysql> CALL my_proc();
ERROR 1644 (45000): An error occurred
...
mysql> SELECT num FROM test;
+------+
| num  |
+------+
|    5 |
+------+


现在,您可以使用DECLARE ... HANDLER statement回滚my_proc()过程中的事务,如下所示。* 请注意,没有事务的my_proc()过程(START TRANSACTIONCOMMIT语句)不会将num回滚到2

DELIMITER $$

CREATE PROCEDURE my_proc() 
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    ROLLBACK;
  END;
  START TRANSACTION;
    UPDATE test SET num = 5;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
  COMMIT;
END$$ 

DELIMITER ;


或者,您可以在my_proc()过程中回滚事务,如下所示:

DELIMITER $$

CREATE PROCEDURE my_proc() 
BEGIN
  DECLARE `_rollback` BOOL DEFAULT 0;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
  BEGIN  
    SET `_rollback` = 1;
  END;
  START TRANSACTION;
    UPDATE test SET num = 5;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
  IF `_rollback` THEN
    ROLLBACK;
  ELSE
    COMMIT;
  END IF;
END$$ 

DELIMITER ;


然后,调用my_proc()不会得到错误,因为错误由DECLARE ... HANDLER语句处理,然后num回滚到2,如下所示:

mysql> CALL my_proc();
...
mysql> SELECT num FROM test;
+------+
| num  |
+------+
|    2 |
+------+

相关问题