所以这里是postgresql 9.6 docs关于Read Committed Isolation Level的完整段落:
Read Committed是PostgreSQL中的默认隔离级别。当一个 transaction使用这个隔离级别,一个SELECT查询(没有FOR UPDATE / SHARE子句仅查看在查询开始之前提交的数据; 它永远不会看到未提交的数据或在此期间提交的更改 并发事务查询执行。实际上是一个SELECT查询 在查询开始的瞬间查看数据库的快照 跑。但是,SELECT确实看到了先前更新执行的效果 在它自己的交易中,即使它们尚未提交。 另请注意,两个连续的SELECT命令可以看到不同的数据, 即使它们属于单一交易,如果是其他交易 事务在第一个SELECT开始之后和之前提交更改 第二个SELECT开始。
基本上是这样的:
SELECT查询只查看在查询开始之前提交的数据,并且永远不会看到在查询执行期间提交的更改 并发交易。
但在最后一句中,它指出:
另请注意,两个连续的SELECT命令可以看到不同的数据, 即使它们属于单一交易,如果是其他交易 事务在第一个SELECT开始之后和之前提交更改 第二个SELECT开始。
对我来说,它看起来很矛盾。有人可以详细说明吗?两个SELECT查询究竟如何在一个事务中看到不同的数据? Isn`t交易是否被隔离?
答案 0 :(得分:2)
是的,这是真的。为了避免这种情况,您需要使用更高的隔离级别:"可重复读取"。 或甚至"可序列化"如果您需要完全隔离您的交易。 请记住,更高的隔离度通过性能支付更高的成本。
您可以在此处找到详细说明:https://www.postgresql.org/docs/9.1/static/transaction-iso.html
以下是一个如何实现的例子:
Connection2更新同一行并提交
Connection1再次读取同一行并获取更新数据
隔离级别是"读取已提交",因此字面上提交的所有内容对其他连接都是可见的。
如果由于某种原因无法使用更高的隔离级别,有一种方法可以防止出现这种意外情况"发生更新:您的Connection1可以使用"选择...进行更新"代替。这将有效地锁定行,直到Connection1的事务提交或回滚。因此Connection2将等待此提交或回滚以便能够更新该行。
答案 1 :(得分:1)
没有矛盾。事务中的两个连续SELECT语句可能会获取不同的结果。考虑一下 - 你开始交易,然后发出
select * from emp;
你得到2条记录。
另一个会话将记录插入到emp和commit中。
在第一个会话中,您再次发出
select * from emp;
你得到3条记录。这是READ COMMITTED隔离级别的预期行为。
示例代码
tmp=# begin ;
BEGIN
tmp=# select * from emp;
id
----
1
2
(2 rows)
tmp=# select * from emp;
id
----
1
2
3
(3 rows)
tmp=# commit;