2016-06-10 31 views
2

是否可以在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

我已经没有太多机会与交易工作,因为大部分的架构我处理过大量基础的MyISAM的; MyISAM根本不支持事务,它可能是您的表使用的存储引擎? – Uueerdo

回答

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

有可能目前没有这样的事情在MySQL。 按MySQL的doc

像MySQL在一般情况下,在插入,删除或更新 许多行的SQL语句,InnoDB的检查唯一性和外键约束 一行接一行。在执行外键检查时,InnoDB在其必须查看的子或父记录上设置共享 行级锁。 InnoDB 立即检查外键约束;该支票不会延迟 到交易提交。根据SQL标准,默认的 行为应该是延迟检查。也就是说,在处理完整个SQL语句之后,仅检查约束条件 。直到 InnoDB实现延迟约束检查,有些事情将是 不可能的,例如使用 外键删除引用自身的记录。

要做到这一点在MySQL中使用中间表,以便同样的问题不会发生,但目前没有干净的方式来做到这一点在MySQL中。

其可能在其他数据库一样Postgresql在这里可以设置模式,以检查约束上的事务提交

SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE } 
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 | 
+1

你的小提琴没有独特的钥匙,使用这个:http://sqlfiddle.com/#!9/3c080/1 – Barmar