ins*_*ity 2 sql postgresql stored-procedures plpgsql psql
假设我有一些PostgreSQL函数,如下所示:
CREATE FUNCTION insertSth() RETURNS void AS $$
BEGIN
INSERT INTO ...;
END;
CREATE FUNCTION removeSthAfterSelect() RETURNS TABLE(...) AS $$
BEGIN
SELECT id INTO some_id ...;
RETURN QUERY SELECT * FROM ...;
DELETE FROM ... WHERE id = some_id;
END;
CREATE FUNCTION justDeleteSth() RETURNS void AS $$
BEGIN
DELETE FROM ...;
END;
CREATE FUNCTION justSelectSth() RETURNS TABLE(...) AS $$
BEGIN
RETURN SELECT * FROM ...;
END;
Run Code Online (Sandbox Code Playgroud)
从我对PostgresSQL函数的理解insertSth,justDeleteSth并将justSelectSth以原子方式执行(?).所以并行执行它们不会搞砸任何东西.
但是,removeSthAfterSelect如果有并行执行,它可能会SELECT id INTO some_id ..找到一些东西,然后同时另一个事务调用justDeleteSth并删除该行id = someId,所以当事务继续时它不会删除任何东西:DELETE FROM ... WHERE id = some_id;意味着它搞砸了.
是这样的吗?有没有办法避免这个问题?例如,说removeSthAfterSelect应该原子地执行?
Cra*_*ger 11
事务具有原子提交的属性,即保证整个事务生效,或者不执行任何事务.
这并不意味着交易无法互动.特别是,在READ COMMITTED模式中,通过另一个事务中途提交的事务可以具有可见效果.即使没有它,同时异常也是可能的和正常的.请参阅有关并发控制的PostgreSQL章节,尤其是事务隔离部分.与独立语句相比,函数语句对并发问题不再具有免疫力.
即使在单个语句中,也可能存在并发问题.陈述不是神奇的原子.人们通常认为,如果他们可以使用CTE,子查询等将所有内容打包到单个查询中,那么它就会神奇地免受并发问题的影响.事实并非如此.
没有函数标签可以说"以原子方式执行",因为您正在寻找的概念在DBMS中不存在.您将获得的最接近的是LOCK TABLE ... IN ACCESS EXCLUSIVE该函数使用的所有表,以便其他任何表都无法触及它们.如果您可以有效地推断并发和事务隔离,那通常是相当过度和不必要的.
很难更具体,因为你正在使用一个非常概括的例子,遗漏了所有的细节.例如,如果您尝试两次删除该行,为什么重要?
你应该研究的一些概念:
READ COMMITTED与SERIALIZABLE事务隔离SELECT ... FOR UPDATE)作为并发操作的一个示例,请查看upsert问题.
但是对于removeSthAfterSelect,如果有并行执行,可能是SELECT id INTO some_id ..找到了什么,然后同时另一个事务调用justDeleteSth并删除id = someId的行,所以当事务继续时它不会删除任何东西: DELETE FROM ... WHERE id = some_id; 意思是它搞砸了.
你说的就好像一个交易停止而另一个交易运行,然后第一个交易继续.通常情况并非如此; 事物可以完全同时运行,许多陈述真正同时发生.
限制行的主要因素是行级锁定.在这种情况下,存在竞争条件,因为两者都DELETE试图获取行的行更新锁.无论哪个获取它将继续并删除该行.另一个DELETE被卡在行锁上,直到获胜的事务提交或回滚.如果它回滚,就好像什么都没发生一样,等待的交易继续正常进行.如果获胜事务提交删除,则等待事务看到锁已被释放,并且(在READ COMMITTED模式中)重新检查WHERE子句谓词以确保该行仍然匹配,发现它不再存在,并继续没有错误,因为删除零行不是错误.
在PL/PgSQL中,如果要强制语句只影响一行,并且RAISE EXCEPTION它与预期的受影响行不匹配,则可以检查受影响的行数.还有INTO STRICT的SELECT.
| 归档时间: |
|
| 查看次数: |
4602 次 |
| 最近记录: |