DELIMITER $$
CREATE PROCEDURE my_proc()
BEGIN
UPDATE test SET num = 5;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
END$$
DELIMITER ;
型 然后,调用my_proc()会得到错误,但num不会回滚到2,如下所示:
mysql> CALL my_proc();
ERROR 1644 (45000): An error occurred
...
mysql> SELECT num FROM test;
+------+
| num |
+------+
| 5 |
+------+
DELIMITER $$
CREATE FUNCTION my_func() RETURNS INT
DETERMINISTIC
BEGIN
UPDATE test SET num = 5;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
RETURN NULL;
END$$
DELIMITER ;
型 然后,调用my_func()得到错误,然后num回滚到2,如下所示:
mysql> SELECT my_func();
ERROR 1644 (45000): An error occurred
...
mysql> SELECT num FROM test;
+------+
| num |
+------+
| 2 |
+------+
2条答案
按热度按时间zxlwwiss1#
不,存储过程不是原子的。
上面显示的伪代码有一个竞态条件。第一个循环,检查一行是否有标志,将返回一个答案,但除非你执行locking read,否则另一个并发会话可能会在你的过程读取该行后立即更改标志。
这就是乐观锁定的效果。除非你发出一个语句来锁定它们,否则它们不会被锁定。所以即使在事务中,你也没有原子锁定。
MySQL支持的原子性是针对事务提交的。事务是原子性的,因为在事务期间所做的所有更改都成功,否则所有更改都会回滚。其他会话无法看到处于部分完成状态的事务。
回复下面的评论:
您可以从应用调用事务中的过程:
字符串
您甚至可以在过程的主体中显式地启动和提交一个事务(或连续的多个事务):
型
但是过程本身并不隐式地启动或提交事务。
ni65a41a2#
默认情况下,procedure不是原子的,而function在MySQL中是原子的。* Atomic**意味着如果有错误就会回滚,我们可以在过程中使用transaction,而不能在函数中使用。
例如,创建
test
表,如下所示:字符串
然后,插入
num
为2
的行,如下所示:型
现在,创建
my_proc()
过程,将num
更新为5
,然后通过SIGNAL statement导致错误,如下所示:型
然后,调用
my_proc()
会得到错误,但num
不会回滚到2
,如下所示:型
实际上,您可以使用
my_proc()
外部的事务将num
回滚到2
,如下所示。* 我的答案解释了如何使用my_proc()
内部的事务将num
回滚到2
:型
接下来,创建
my_func()
函数,将num更新为5,然后通过SIGNAL
语句导致错误,如下所示:型
然后,调用
my_func()
得到错误,然后num
回滚到2
,如下所示:型