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