我的存储过程的基本结构是,
BEGIN .. Declare statements .. START TRANSACTION; .. Query 1 .. .. Query 2 .. .. Query 3 .. COMMIT; END
**MySQL版本:**5.1.61-0ubuntu0.11.10.1-日志
当前,如果“查询2”失败,则提交“查询1”的结果。
zi8p0yeb1#
看一看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;
0sgqnhkj2#
这只是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
0qx6xfy63#
[* 这只是其他答案中未涉及的解释 *]至少在MySQL的最新版本中,您的第一个查询不是提交的。如果您在同一会话下查询它,您将看到更改,但如果您从不同的会话查询它,则更改不存在,它们没有提交。
当您打开一个事务,并且其中的查询失败时,该事务保持打开状态,它不会提交也不会回滚更改。因此,请小心,使用先前的查询(如SELECT ... FOR SHARE/UPDATE、UPDATE、INSERT或任何其他锁定查询)锁定的任何表/行都将保持锁定状态,直到该会话被终止(并执行回滚),或者直到后面的查询显式提交它(COMMIT)或implicitly,从而使得部分改变永久(这可能在数小时后事务处于等待状态时发生)。这就是为什么解决方案需要声明处理程序,以便在发生错误时立即使用ROLLBACK。额外在处理程序内部,您还可以使用RESIGNAL重新引发错误,否则存储过程将执行 “Successfully”:
SELECT ... FOR SHARE/UPDATE
UPDATE
INSERT
COMMIT
ROLLBACK
RESIGNAL
BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; START TRANSACTION; -- .. Query 1 .. -- .. Query 2 .. -- .. Query 3 .. COMMIT; END;
332nm8kg4#
下面是一个事务的示例,该事务将在出错时回滚并返回错误代码。
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。希望这能有所帮助。
4条答案
按热度按时间zi8p0yeb1#
看一看http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html
基本上,您需要声明将调用回滚的错误处理程序
0sgqnhkj2#
这只是rkosegi代码的替代品,
0qx6xfy63#
[* 这只是其他答案中未涉及的解释 *]
至少在MySQL的最新版本中,您的第一个查询不是提交的。
如果您在同一会话下查询它,您将看到更改,但如果您从不同的会话查询它,则更改不存在,它们没有提交。
这是怎么回事?
当您打开一个事务,并且其中的查询失败时,该事务保持打开状态,它不会提交也不会回滚更改。
因此,请小心,使用先前的查询(如
SELECT ... FOR SHARE/UPDATE
、UPDATE
、INSERT
或任何其他锁定查询)锁定的任何表/行都将保持锁定状态,直到该会话被终止(并执行回滚),或者直到后面的查询显式提交它(COMMIT
)或implicitly,从而使得部分改变永久(这可能在数小时后事务处于等待状态时发生)。这就是为什么解决方案需要声明处理程序,以便在发生错误时立即使用
ROLLBACK
。额外
在处理程序内部,您还可以使用
RESIGNAL
重新引发错误,否则存储过程将执行 “Successfully”:332nm8kg4#
下面是一个事务的示例,该事务将在出错时回滚并返回错误代码。
这是假设自动提交设置为0。希望这能有所帮助。