含IF语句的MySQL事务出现SQL语法错误,如何解决?
修复MySQL转账事务中的语法错误(Error 1064)
错误原因
你碰到的Error Code: 1064是因为**IF、ROW_COUNT()这类流程控制逻辑属于MySQL存储程序(存储过程/函数)专属语法**,不能直接在普通交互式SQL会话里执行BEGIN...END代码块。MySQL默认客户端只支持执行基础SQL语句,不识别存储程序特有的流程控制语法。
方案1:封装为存储过程(推荐用于生产环境)
把转账逻辑写成存储过程,就能正常使用流程控制语句了:
-- 临时修改语句分隔符,避免存储过程内的分号被提前解析 DELIMITER // CREATE PROCEDURE TransferirMonto(IN cuenta_origen INT, IN cuenta_destino INT, IN monto_transferir DECIMAL(10,2)) BEGIN -- 加行锁防止并发修改 SELECT saldo FROM cuentas WHERE id_cuenta = cuenta_origen FOR UPDATE; SELECT saldo FROM cuentas WHERE id_cuenta = cuenta_destino FOR UPDATE; -- 尝试扣除源账户余额(仅当余额足够时执行) UPDATE cuentas SET saldo = saldo - monto_transferir WHERE id_cuenta = cuenta_origen AND saldo >= monto_transferir; -- 判断扣除操作是否成功 IF ROW_COUNT() = 0 THEN ROLLBACK; SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Saldo insuficiente en la cuenta de origen'; ELSE -- 增加目标账户余额 UPDATE cuentas SET saldo = saldo + monto_transferir WHERE id_cuenta = cuenta_destino; COMMIT; END IF; END // -- 恢复默认分隔符 DELIMITER ;
调用存储过程执行转账:
CALL TransferirMonto(1, 2, 100.00);
方案2:无存储过程的临时执行写法
如果只是临时测试,不想创建存储过程,可以调整为如下写法(利用会话变量替代流程控制):
START TRANSACTION; -- 查询并锁定源账户余额 SET @saldo_disponible = (SELECT saldo FROM cuentas WHERE id_cuenta = 1 FOR UPDATE); IF @saldo_disponible >= 100.00 THEN UPDATE cuentas SET saldo = saldo - 100.00 WHERE id_cuenta = 1; UPDATE cuentas SET saldo = saldo + 100.00 WHERE id_cuenta = 2; COMMIT; SELECT 'Transferencia exitosa' AS resultado; ELSE ROLLBACK; SELECT 'Saldo insuficiente en la cuenta de origen' AS error; END IF;
额外注意事项
FOR UPDATE行锁的使用是正确的,能避免并发转账时的脏数据问题,保证事务的一致性。SIGNAL语句仅支持在存储程序中使用,所以临时写法里用SELECT返回错误信息替代。
内容的提问来源于stack exchange,提问作者pamela giron
相关产品推荐
相关产品推荐

