PostgreSQL:我是否需要锁定 table 以避免在使用子查询查找 JSONB 数组中的更新索引的更新期间出现并发错误?
PostgreSQL: Do I need to lock table to avoid concurrency errors during update that use a subquery to find the index o update in a JSONB array?
假设我想更新 customers
table 中的 JSONB 列 contacts
(对象数组),并且我想更新基于数组的对象的值由于子查询,在其索引上,我是否需要在执行期间锁定 table 以防止更新以避免并发问题?
换句话说,是否可以在我的两次查询执行之间更改table,因此我通过子查询选择的索引将过时?
with contact_email as (
select ('{' || index - 1 || ', value}')::text[] as path from customers
cross join jsonb_array_elements(contacts) with ordinality arr(contact, index)
where contact->>type = 'email' and name = 'john'
)
update customers
set contacts = jsonb_set(contacts,contact_email.path,'"john@example.com"', false)
from contact_email
where and name = 'john'
-- `customers` table has a `name` column and a `contacts` column (jsonb)
-- `contacts` column contains things like `[{"type":"email","value":"x@y.z", …}]`
在上面的示例中,如果 contacts
列中的数组在 table 读取(子查询)和更新(主查询)之间发生更改,则选择的索引将变得错误:然后我会更新错误的数组条目。
如果有什么不清楚,我可以编辑我的问题并添加更多详细信息。
查询的两部分将看到相同的数据库快照,因此数据始终一致。
如果某些并发事务在读取时间和写入时间之间更改行,结果取决于您的隔离级别:
如果您是 运行 默认 READ COMMITTED
隔离,则更新将覆盖该更改或不执行任何操作(后者如果 name
已更改)
如果您 运行 REPEATABLE READ
或更高,您将得到 序列化错误 并且必须重复语句
假设我想更新 customers
table 中的 JSONB 列 contacts
(对象数组),并且我想更新基于数组的对象的值由于子查询,在其索引上,我是否需要在执行期间锁定 table 以防止更新以避免并发问题?
换句话说,是否可以在我的两次查询执行之间更改table,因此我通过子查询选择的索引将过时?
with contact_email as (
select ('{' || index - 1 || ', value}')::text[] as path from customers
cross join jsonb_array_elements(contacts) with ordinality arr(contact, index)
where contact->>type = 'email' and name = 'john'
)
update customers
set contacts = jsonb_set(contacts,contact_email.path,'"john@example.com"', false)
from contact_email
where and name = 'john'
-- `customers` table has a `name` column and a `contacts` column (jsonb)
-- `contacts` column contains things like `[{"type":"email","value":"x@y.z", …}]`
在上面的示例中,如果 contacts
列中的数组在 table 读取(子查询)和更新(主查询)之间发生更改,则选择的索引将变得错误:然后我会更新错误的数组条目。
如果有什么不清楚,我可以编辑我的问题并添加更多详细信息。
查询的两部分将看到相同的数据库快照,因此数据始终一致。
如果某些并发事务在读取时间和写入时间之间更改行,结果取决于您的隔离级别:
如果您是 运行 默认
READ COMMITTED
隔离,则更新将覆盖该更改或不执行任何操作(后者如果name
已更改)如果您 运行
REPEATABLE READ
或更高,您将得到 序列化错误 并且必须重复语句