正如你注意到的那樣,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