正如你注意到的那样,json[b]
的值(就像PostgreSQL中的其他类型一样)只能作为一个整体被编辑为UPDATE
。
8.14.2.有效地设计JSON文件:存储在表中时
JSON数据受到相同的并发控制的考虑任何其它数据类型。尽管存储大型文档是切实可行的,但请记住,任何更新都会获得整行上的行级锁定。考虑将JSON文档限制为可管理的大小,以减少更新事务之间的锁争用。 理想情况下,JSON文档应该分别代表原子数据,商业规则指定的数据不能合理地进一步细分为更小的数据库,这些数据可以独立修改。
所以,你一个显而易见的解决方案是将您的JSON阵列&店它的元素,而不是(f.ex.在接线表,其中一对多关系到你的原始表)。
但是,您也可以通过其他几种方式避免这些“丢失的更新”(但这些确实不是那些理想的方式)。
- 原子
UPDATE
小号
让我给你介绍一个类比。如果你想在任何RDBMS的计数器,你通常会做这样的:
UPDATE counter SET value = value + 1
这是(当然)不受丢失更新。但是,当你做
SELECT value FROM counter
-- do something in client & bind the selected value + 1 to the next query:
UPDATE counter SET value = ?
这是受到丢失更新。因为,在SELECT
& UPDATE
声明之间,另一个交易可能会在当前值之前更新该值。如果发生这种情况,那些UPDATE
就会丢失。您最有可能在jsonb
列中执行此类UPDATE
。
第一条语句的jsonb
对方可能看起来像这些之一:
-- to append a JSON array element to the root JSON array
UPDATE t SET jsonb_col = jsonb_col || '[{"a":1}]';
-- to append a JSON array element to an array, located on the path: 'a' (requires 9.6+)
UPDATE t SET jsonb_col = jsonb_insert(jsonb_col, ARRAY['a', '-1'], '{"a":1}', TRUE);
-- Notes: TRUE means that insert AFTER ... -1 (in the path) means after the LAST ELEMENT
然而,这些(通常情况下)很难实现与奥姆斯。
- 锁定
如果您不能使用上面的查询,则必须确保只有一个事务可以UPDATE
同时在表中的行。
2/A。 悲观锁
这样一来,你告诉RDBMS明确指出你SELECT
编行特定原因:FOR UPDATE
。 F.ex. ActiveRecord supports this。
2/B。 乐观锁
有了这个,你必须使用/在您UPDATE
一个version
列,即:
UPDATE t
SET jsonb_col = ?,
t_version = t_version + 1
WHERE t_version = ?
这样一来,就没有办法宽松的UPDATE
,但你的陈述可能不会做什么都没有。如果它没有更新任何行,您必须自己检查行数(在您的客户端)&重试。
F.ex. ActiveRecord supports this too。
了解更多关于这些:Optimistic vs. Pessimistic locking
- 串行事务像乐观锁系溶液,除了它不
Serializable transactions作品需要特殊的版本列。相反,RDBMS将使用谓词锁定来避免丢失的更新。此外,当序列化失败发生时,您需要重新尝试整个事务。
如何更容易覆盖'jsonb'列而不是'varchar'或'int4'列? – Brian