在函数内调用过程会引发MySQL错误1422

在函数内调用过程会引发MySQL错误1422,mysql,sql,stored-procedures,transactions,sql-function,Mysql,Sql,Stored Procedures,Transactions,Sql Function,我正在建立一个“银行”,作为我正在学习的数据库课程的作业。我创建了一个存储函数,它在变量中包含一些,例如帐户ID、客户ID和PIN码,并对此进行检查以查看提交的数据是否有效。如果数据有效,该过程将更新帐户余额以表示货币交易。然后它“返回”提交的数据是否有效。以下是程序代码: DELIMITER // CREATE PROCEDURE retrieveMoney ( IN holder INT, IN pin VARCHAR(4), IN account INT,

我正在建立一个“银行”,作为我正在学习的数据库课程的作业。我创建了一个存储函数,它在变量中包含一些
,例如帐户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 ;
不幸的是,这不起作用,我仍然得到以下错误:

错误1422(HY000):存储函数或触发器中不允许显式或隐式提交。


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

有许多语句会导致隐式提交,这些语句都不能在存储函数或触发器内部使用,也不能在从存储函数或触发器调用的存储过程中使用,因为这在其净效应上并没有什么不同

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

在这种情况下,如果可以在单个查询运行时提交事务,那就没有意义了。。。这就是
START TRANSACTION
所做的,如果事务正在运行——它隐式提交当前事务,并启动一个新事务

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


有许多语句会导致隐式提交,但这些语句都不能在存储函数或触发器内部使用,也不能在从存储函数或触发器调用的存储过程中使用,因为这实际上在其净效果上没有什么不同

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

在这种情况下,如果可以在单个查询运行时提交事务,那就没有意义了。。。这就是
START TRANSACTION
所做的,如果事务正在运行——它隐式提交当前事务,并启动一个新事务

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


是的。错误信息显示它很响。是的。错误信息很响亮。回答得很好,谢谢!你这样说真有道理!回答得很好,谢谢!你这样说真有道理!