可以在MySQL中创建原子事务吗?
考虑一下我有表'类别'这些行:
id|name
--|---------
1 |'tablets'
2 |'phones'
列name
是我的主键。
如果我尝试:
START TRANSACTION;
update "category" set name = 'phones' where id = 1;
update "category" set name = 'tablets' where id = 2;
COMMIT;
我得到了:
ERROR: duplicate key value violates unique constraint
"category_name_key"
DETAIL: Key (name)=(tablets) already exists.
我的期望是只能在提交期间进行约束检查。这可能与MySQL有关吗?
答案 0 :(得分:1)
是不可能的,因为mysql MySQL进程更新在每次单行更新后强制执行UNIQUE(和其他)约束的检查,而不是 - 就像它应该做的那样 - 在完成整个UPDATE语句之后。
然后你应该使用中间更新
update "category" set name = 'temp' where id = 1;
update "category" set name = 'tablets' where id = 2;
update "category" set name = 'phone' where id = 1;
答案 1 :(得分:1)
目前在MySQL中没有这样的东西。 根据mysql doc
与MySQL一般,在插入,删除或删除的SQL语句中 更新许多行,InnoDB检查UNIQUE和FOREIGN KEY约束 行由行。执行外键检查时,InnoDB设置共享 它必须查看的子记录或父记录上的行级锁定。 InnoDB的 立即检查外键约束;支票不会延期 到事务提交。根据SQL标准,默认 行为应该推迟检查。也就是说,只有约束 在处理完整个SQL语句后检查。直到 InnoDB实现了延迟约束检查,有些事情将是 不可能,例如删除使用a引用自身的记录 外键。
要在Mysql中使用中间表执行此操作,以便同样的问题不会发生,但目前在mysql中没有干净的方法。
它可以在其他数据库中使用,例如Postgresql,您可以在事务提交后设置模式以检查约束
SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE }
答案 2 :(得分:1)
你使这个例子过于简单,所以即使这解决了你的问题,也许不是你想要的。
<强> SQL Fiddle Demo 强>
UPDATE `category`
SET id = CASE WHEN name = 'phones' THEN 1
WHEN name = 'tablets' THEN 2
END
WHERE name in ('tablets', 'phones');
<强>输出强>
| id | name |
|----|---------|
| 2 | tablets |
| 1 | phones |