首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于锁的postgresql阻塞的乐观锁定

基于锁的postgresql阻塞的乐观锁定
EN

Database Administration用户
提问于 2020-04-26 16:36:19
回答 1查看 1.2K关注 0票数 0

我试图在postgresql中使用乐观锁,但我似乎误解了它应该如何工作。我认为,如果我使用“可序列化”隔离级别,那么每个事务都会表现得好像其他事务不存在一样,而且就在提交时,任何检查都会完成,事务最终会中止。但是,在我所做的测试中,事务正在影响其他事务,也就是说,一个事务可能阻塞在一个锁中。这是我正在做的测试:

首先,创建db:

代码语言:javascript
复制
CREATE USER myuser WITH PASSWORD '1234';
CREATE DATABASE tempdb;
GRANT ALL PRIVILEGES ON DATABASE tempdb to myuser;
\connect tempdb;
CREATE TABLE temptable (
    id        integer PRIMARY KEY,
    name       varchar(40) NOT NULL
);
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO myuser;

然后,创建两个python程序。

第一个将尝试插入一行,然后在提交事务之前休眠10秒:

代码语言:javascript
复制
import time
import psycopg2

def main():
    conn = psycopg2.connect(dbname='tempdb', host='localhost', user='myuser', password='1234')
    cur = conn.cursor()
    cur.execute("begin transaction isolation level serializable")
    cur.execute("insert into temptable (id, name) values (1, 'my name');")
    time.sleep(10)
    cur.execute("commit")
    print('test finished')

if __name__ == '__main__':
    main()

第二种方法将尝试做几乎相同的事情,但是它不会在10秒内睡觉:

代码语言:javascript
复制
import time
import psycopg2

def main():
    conn = psycopg2.connect(dbname='tempdb', host='localhost', user='myuser', password='1234')
    cur = conn.cursor()
    cur.execute("begin transaction isolation level serializable")
    cur.execute("insert into temptable (id, name) values (1, 'my other name');")
    cur.execute("commit")
    print('test finished')

if __name__ == '__main__':
    main()

如果我运行tem1.py,然后,在其他窗口中,tem2.py,tem2.py会挂起,直到tem1.py提交为止。但是,我所期望的是tem2.py会插入行,提交,然后,当tem1.py试图提交时,它会得到一个错误。

我做错什么了吗?在postgresql中可以做我想做的事情吗?

(我使用postgresql 10.12)

EN

回答 1

Database Administration用户

回答已采纳

发布于 2020-04-26 17:15:20

问:然而,在我所做的测试中,事务正在影响其他事务,也就是说,一个事务可能阻塞在一个锁中。

在可序列化隔离级别上不相互影响的并发事务并不意味着任何一个事务都不会锁定其他事务。一旦并发事务处理相同的数据,数据库中的锁就不可避免。

不相互影响意味着,任何特定事务的结果与其他事务不同时处理相同数据时的结果没有什么不同。

完成事务所需的时间,或者是否必须等待锁被释放,都不算作结果。结果是读取、写入或返回给调用者的行和值。

问:但是,我所期望的是tem2.py会插入行,提交,然后,当tem1.py试图提交时,它会得到一个错误。

该错误涉及违反唯一约束。约束检查可以是延迟的,也可以是即时的,与隔离级别无关,默认情况下它们是即时的。

如果将唯一列声明为id integer PRIMARY KEY DEFERRABLE INITIALLY DEFERRED,事务#2中的插入将不会挂起,但事务#2将在提交时挂起,直到事务#1提交或中止为止。

问:在postgresql中可以做我想做的事情吗?

如果您希望确保第二个事务(插入第二个事务)成功,因为提交比先插入的另一个事务更快,我认为这是不可能的。从可序列化隔离逻辑的角度来看,哪个事务失败并不重要。任何事务都可能失败,调用方必须随时准备根据SQLSTATE (错误代码)作出适当的反应。

票数 1
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/265868

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档