简而言之:
我有Postgresql数据库,我通过Python的psycopg2
模块连接到该数据库。这样的脚本可能如下所示:
import psycopg2
# connect to my database
conn = psycopg2.connect(dbname="<my-dbname>",
user="postgres",
password="<password>",
host="localhost",
port="5432")
cur = conn.cursor()
ins = "insert into testtable (age, name) values (%s,%s);"
data = ("90", "George")
sel = "select * from testtable;"
cur.execute(sel)
print(cur.fetchall())
# prints out
# [(100, 'Paul')]
#
# db looks like this
# age | name
# ----+-----
# 100 | Paul
# insert new data - no commit!
cur.execute(ins, data)
# perform the same select again
cur.execute(sel)
print(cur.fetchall())
# prints out
# [(100, 'Paul'),(90, 'George')]
#
# db still looks the same
# age | name
# ----+-----
# 100 | Paul
cur.close()
conn.close()
也就是说,我连接到脚本开头的那个数据库:
age | name
----+-----
100 | Paul
我执行SQL select并仅检索Paul
数据。然后我做SQL插入,但没有任何提交,但第二个SQL选择仍然提取Paul
和George
- 我不想要这样。我已查看了psycopg
和Postgresql文档,并了解了ISOLATION LEVEL
(see Postgresql和see psycopg2)。在Postgresql文档(13.2.1。读提交的隔离级别)中,它明确地说:
但是,SELECT确实看到了在自己的事务中执行的先前更新的效果,即使它们尚未提交。
我已经尝试过不同的隔离级别,我明白,我认为Read Committed
和Repeatable Read
并不是Serializable
可能会有效,但确实如此不 - 意味着我仍然可以使用select
获取未提交的数据。
我可以conn.set_isolation_level(0)
,其中0
代表psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT
,或者我可以将execute
命令包含在with
语句中see )。
毕竟,我有点困惑,我是否理解交易和隔离(以及select
没有commit
的行为是完全正常的)或不是。有人可以启发这个话题吗?
答案 0 :(得分:2)
您的两个SELECT
语句使用相同的连接,因此使用相同的事务。来自the psycopg manual you linked:
默认情况下,第一次将命令发送到数据库时......会创建一个新事务。以下数据库命令将在同一事务的上下文中执行。
因此,您的代码等同于以下内容:
BEGIN TRANSACTION;
select * from testtable;
insert into testtable (age, name) values (90, 'George');
select * from testtable;
ROLLBACK TRANSACTION;
隔离级别控制事务与其他事务交互的方式。在事务中,您始终可以看到该事务中命令的效果。
如果要隔离代码的两个不同部分,则需要打开两个与数据库的连接,每个连接(除非您启用自动提交)创建一个单独的事务。
请注意,根据已链接的文档,创建新光标是不够的:
...不仅是第一个游标发出的命令,而是由同一个连接创建的所有游标发出的命令
答案 1 :(得分:1)
使用自动提交无法解决您的问题。当autocommit为1时,每次插入和更新都会自动提交到数据库,所有后续读取都会看到该数据。
不希望看到您已经写入数据库的数据,这是最不寻常的。但如果这是你想要的,你需要两个独立的连接,你必须确保在提交之前执行你的选择。