在函数内调用过程会抛出MySQL ERROR 1422

时间:2014-09-29 09:28:00

标签: mysql sql stored-procedures transactions sql-function

我正在建立一个"银行"作为我正在参加的数据库课程的作业。我创建了一个存储函数,它接受一些IN变量,例如帐户ID,客户ID和PIN号,并对此进行检查以查看提交的数据是否有效。如果数据有效,则该过程更新帐户余额以表示货币交易。然后"返回"提交的数据是否有效。以下是该过程的代码:

DELIMITER //
CREATE PROCEDURE retrieveMoney (
    IN holder INT,
    IN pin VARCHAR(4),
    IN account INT,
    IN amount FLOAT,
    OUT success INT
)
BEGIN
    START TRANSACTION;
    SELECT COUNT(id) INTO success FROM account_holder WHERE id=holder AND pin=pin;
    IF success IS NOT NULL THEN
        IF (SELECT balance-amount FROM account WHERE id=account) >= 0 THEN
            UPDATE account SET balance = balance-amount WHERE id=account;
            CALL logTransaction(account,NULL,amount);
            COMMIT;
        ELSE ROLLBACK;
        END IF;
    ELSE ROLLBACK;
    END IF;
END//
DELIMITER ;

我想更容易查看过程的输出,因为我不允许在函数中使用事务,我选择编写包装函数,如下所示:

DELIMITER //
CREATE FUNCTION retrieveMoney (
    holder INT,
    pin VARCHAR(4),
    account INT,
    amount FLOAT
)
RETURNS INT
BEGIN
    CALL retrieveMoney(holder,pin,account,amount,@success);
    RETURN @success;
END//
DELIMITER ;

不幸的是,这不起作用,我仍然会收到以下错误:

ERROR 1422 (HY000): Explicit or implicit commit is not allowed in stored function or trigger.

这是因为我在函数内部调用了包含事务的过程吗?

1 个答案:

答案 0 :(得分:3)

有许多语句导致隐式提交,并且这些语句都不能在存储函数或触发器中或在从存储函数或触发器调用的存储过程中使用因为它的净效果并没有什么不同。

片刻的反思解释了其原因:存储的函数(和触发器)在查询运行时执行 。它们始终无一例外地在查询开始后开始执行,并在查询完成之前完成执行。它们还可以在执行单个查询期间多次运行,尤其是当查询涉及多行时。

从这个角度来看,如果在单个查询正在运行时COMMIT交易是可能的,那将是没有意义的......如果是事务,START TRANSACTION的作用是什么正在运行 - 它隐式提交当前事务,并启动一个新事务。

这在存储过程中很好,只要你不在另一个查询的中间调用它(通过存储的函数或触发器,这是在另一个中间调用过程的唯一方法)查询)但不支持在这里做你正在做的事情......即使没有运行的事务,仍然无法在正在运行的查询中启动事务。

http://dev.mysql.com/doc/refman/5.6/en/implicit-commit.html