MySQL中的过程是原子的吗?

6bc51xsx  于 5个月前  发布在  Mysql
关注(0)|答案(2)|浏览(58)

正如标题所说,MySQL中的过程是原子的吗?

for (..)
  <check_if_row_has_flag>
for (..)
  <update_row>

字符串
原子地工作?
有趣的是,我在谷歌上找不到太多关于这方面的信息,除了2009年的一个论坛帖子。

zxlwwiss

zxlwwiss1#

不,存储过程不是原子的。
上面显示的伪代码有一个竞态条件。第一个循环,检查一行是否有标志,将返回一个答案,但除非你执行locking read,否则另一个并发会话可能会在你的过程读取该行后立即更改标志。
这就是乐观锁定的效果。除非你发出一个语句来锁定它们,否则它们不会被锁定。所以即使在事务中,你也没有原子锁定。
MySQL支持的原子性是针对事务提交的。事务是原子性的,因为在事务期间所做的所有更改都成功,否则所有更改都会回滚。其他会话无法看到处于部分完成状态的事务。
回复下面的评论:
您可以从应用调用事务中的过程:

START TRANSACTION;
CALL MyProcedure();
COMMIT;

字符串
您甚至可以在过程的主体中显式地启动和提交一个事务(或连续的多个事务):

CREATE PROCEDURE MyProcedure()
BEGIN
    START TRANSACTION;
    ...UPDATE, INSERT, DELETE, blah blah...
    COMMIT;
END


但是过程本身并不隐式地启动或提交事务。

ni65a41a

ni65a41a2#

默认情况下,procedure不是原子的,而function在MySQL中是原子的。* Atomic**意味着如果有错误就会回滚,我们可以在过程中使用transaction,而不能在函数中使用。
例如,创建test表,如下所示:

CREATE TABLE test (
  num int
);

字符串
然后,插入num2的行,如下所示:

INSERT INTO test (num) VALUES (2);


现在,创建my_proc()过程,将num更新为5,然后通过SIGNAL statement导致错误,如下所示:

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 |
+------+


实际上,您可以使用my_proc()外部的事务将num回滚到2,如下所示。* 我的答案解释了如何使用my_proc()内部的事务将num回滚到2

BEGIN;
CALL my_proc();
ROLLBAKC;


接下来,创建my_func()函数,将num更新为5,然后通过SIGNAL语句导致错误,如下所示:

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 |
+------+

相关问题