我有一个表标记,它具有以下结构和值:
+----+----------+-------+
| id | name | order |
+----+----------+-------+
| 42 | 'foo' | 1 |
+----+----------+-------+
| 43 | 'bar' | 3 |
+----+----------+-------+
| 44 | 'baz' | 2 |
+----+----------+-------+
ID 是内部PK,名称是显示名称,订单(唯一)是必须显示这些代码的顺序('foo','baz','bar')。可以创建新标签,删除现有标签,并重新排序所有标签。
我想我会插入新标签的方式遇到问题。我需要做一些像(伪代码)的事情:
begin transaction A;
select max("order") + 1 into next_order from Tag;
insert into Tag("name", "order") values('blah', next_order);
commit A;
当然,同时可以运行另一个事务:
begin transaction B;
select max("order") + 1 into next_order from Tag;
insert into Tag("name", "order") values('bluh', next_order);
commit B;
让我们采用最高的事务隔离级别 SERIALIZABLE ,我明白它可以保护我免受幻读,即使“A”提交而“B”运行,“B”也不会看到新的行('blah',4)。
不幸的是,“B”和“A”会选择相同的max(“order”)+ 1,而“A”和“B”提交后的表格看起来像:
+----+------------------+
| id | name | order |
+----+----------+-------+
| 42 | 'foo' | 1 |
+----+----------+-------+
| 43 | 'bar' | 3 |
+----+----------+-------+
| 44 | 'baz' | 2 |
+----+----------+-------+
| 45 | 'blah' | 4 |
+----+----------+-------+
| 46 | 'bluh' | 4 |
+----+----------+-------+
我希望我错了,是吗?
如果我不是,那么在表中原子地处理“行顺序”的常见模式是什么?在插入新行时我应该锁定整个表吗?或者我应该使用“order”列没有唯一约束,'blah'和'bluh'插入顺序是未定义的,它们都是第4个?
提前感谢您的建议。
答案 0 :(得分:0)
如果用户删除标记或想要更改订单,该怎么办?
我会锁定桌子。您可能需要触发器才能插入/更新/删除。
因此插入应该使用order = null
正常工作,并将事务逻辑放在触发器中。