SQL 命令 SELECT 从 Postgresql 数据库中获取未提交的数据
SQL command SELECT fetches uncommitted data from Postgresql database
简而言之:
我有 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 select 仍然获取 Paul
和 George
- 我不想要那个.我查看了 psycopg
和 Postgresql 文档,发现了 ISOLATION LEVEL
(see Postgresql and see psycopg2)。在 Postgresql 文档中(在 13.2.1.Read Committed Isolation Level 下)它明确表示:
However, SELECT does see the effects of previous updates executed within its own transaction, even though they are not yet committed.
我已经尝试过不同的隔离级别,据我所知,Read Committed
和 Repeatable Read
不起作用,我认为 Serializable
可能有效,但它没有 - - 这意味着我仍然可以使用 select
获取未提交的数据。
我可以做 conn.set_isolation_level(0)
,其中 0
表示 psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT
,或者我可以将 execute
命令包装在 with
语句中(see).
毕竟,我有点困惑,我是否了解事务和隔离(select
没有 commit
的行为是完全正常的)。有人能给我讲讲这个话题吗?
您的两个 SELECT
语句使用相同的连接,因此使用相同的事务。来自 the psycopg manual you linked:
By default, the first time a command is sent to the database ... a new transaction is created. The following database commands will be executed in the context of the same transaction.
因此,您的代码等同于以下内容:
BEGIN TRANSACTION;
select * from testtable;
insert into testtable (age, name) values (90, 'George');
select * from testtable;
ROLLBACK TRANSACTION;
隔离级别控制事务如何与其他事务交互。在事务中,您始终可以看到命令在该事务中的效果。
如果您想隔离代码的两个不同部分,您需要打开两个数据库连接,每个连接(除非您启用自动提交)都会创建一个单独的事务。
请注意,根据已链接的文档,创建新游标是不够的:
...not only the commands issued by the first cursor, but the ones issued by all the cursors created by the same connection
使用自动提交不会解决您的问题。当自动提交为 1 时,每次插入和更新都会自动提交到数据库,所有后续读取都将看到该数据。
不想看到您已写入数据库的数据是最不寻常的。但如果那是你想要的,你需要两个单独的连接,你必须确保你的 select 在提交之前执行。
简而言之:
我有 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 select 仍然获取 Paul
和 George
- 我不想要那个.我查看了 psycopg
和 Postgresql 文档,发现了 ISOLATION LEVEL
(see Postgresql and see psycopg2)。在 Postgresql 文档中(在 13.2.1.Read Committed Isolation Level 下)它明确表示:
However, SELECT does see the effects of previous updates executed within its own transaction, even though they are not yet committed.
我已经尝试过不同的隔离级别,据我所知,Read Committed
和 Repeatable Read
不起作用,我认为 Serializable
可能有效,但它没有 - - 这意味着我仍然可以使用 select
获取未提交的数据。
我可以做 conn.set_isolation_level(0)
,其中 0
表示 psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT
,或者我可以将 execute
命令包装在 with
语句中(see).
毕竟,我有点困惑,我是否了解事务和隔离(select
没有 commit
的行为是完全正常的)。有人能给我讲讲这个话题吗?
您的两个 SELECT
语句使用相同的连接,因此使用相同的事务。来自 the psycopg manual you linked:
By default, the first time a command is sent to the database ... a new transaction is created. The following database commands will be executed in the context of the same transaction.
因此,您的代码等同于以下内容:
BEGIN TRANSACTION;
select * from testtable;
insert into testtable (age, name) values (90, 'George');
select * from testtable;
ROLLBACK TRANSACTION;
隔离级别控制事务如何与其他事务交互。在事务中,您始终可以看到命令在该事务中的效果。
如果您想隔离代码的两个不同部分,您需要打开两个数据库连接,每个连接(除非您启用自动提交)都会创建一个单独的事务。
请注意,根据已链接的文档,创建新游标是不够的:
...not only the commands issued by the first cursor, but the ones issued by all the cursors created by the same connection
使用自动提交不会解决您的问题。当自动提交为 1 时,每次插入和更新都会自动提交到数据库,所有后续读取都将看到该数据。
不想看到您已写入数据库的数据是最不寻常的。但如果那是你想要的,你需要两个单独的连接,你必须确保你的 select 在提交之前执行。