Open codetalks-new opened 5 years ago
end,commit
rollback
在上面事务逻辑中,事务中出错之后会导致所有执行都回滚. 如果要允许部分成功.则需要使用保存点.
savepoint <savepoint_name>
rollback to savepoint <savepoint_name>
release savepoint <savepoint_name>
对于 DDL 支持事务是 PSQL 的独有强大特性. 一般的 DDL 命令都支持事务.(drop database,create tablespace,drop tablespace 操作除外)
先看一个例子.
左边的事务受其他提交的事务的影响,两次返回的和不一样.这就是因为 PSQL 默认的事务的隔离级别是读提交. 要想左边的事务,一直读到的是同样的值可以采用可重复读的隔离级别. 示例如下:
read committed
repeatable read
read uncommited
serializable
隔离级别对应常见的一些问题.
所以可以这么理解,一般另一个事务中的 update 会可能导致不可重复读 (update 修改了数据.) 而 insert 和 delete 语句可能导致幻读(insert,delete 修改了数据集). 不过 update 和 delete 也会生成不可重复读,比如一个统计语句的查询数据结果就会受到 insert,delete 语句的影响.
update
insert
delete
如下图,删除语句的执行结果为空. 因为.
PSQL 多版本并发控制的要读提交是在每一个命令开始时,就创建一个数据的新的快照(包含此刻所有已经提交的事务的数据更新).当前事务的后续语句能看到其他情况下并发提交的事务的变更.
具体来说, delete 开始执行时,收集了匹配的行,但是同时也知道其他正在进行中的事务会影响到匹配的行, delete 将其放到 可能会变更的行的列表. 当其他事务都提交了之后, delete 会重新评估可能会变更列表里的行.如果对应已经被删除或者已经不匹配则忽略. 也就是说 delete 最终看到的是提交之后的数据版本.
对于 select for update 或 select for share,锁定和返回给用户的数据也是更新后的版本.
select for update
select for share
它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。 因为乐观锁比较适用于读多写少的情况.
乐观并发控制的事务包括3个阶段:
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。
适用写多读少的情况.
PSQL 中的并发控制采用 (MVCC), MVCC 的一大优点就是读写互相不阻塞.
MVCC意图解决读写锁造成的多个、长时间的读操作饿死写操作问题。每个事务读到的数据项都是一个历史快照(snapshot)并依赖于实现的隔离级别。写操作不覆盖已有数据项,而是创建一个新的版本,直至所在操作提交时才变为可见。快照隔离使得事物看到它启动时的数据状态。 MVCC使用时间戳 (TS), 或“自动增量的事务ID”实现“事务一致性”。MVCC可以确保每个事务(T)通常不必“读等待”数据库对象(P)。这通过对象有多个版本,每个版本有创建时间戳 与废止时间戳 (WTS)做到的。
MVCC意图解决读写锁造成的多个、长时间的读操作饿死写操作问题。每个事务读到的数据项都是一个历史快照(snapshot)并依赖于实现的隔离级别。写操作不覆盖已有数据项,而是创建一个新的版本,直至所在操作提交时才变为可见。快照隔离使得事物看到它启动时的数据状态。
MVCC使用时间戳 (TS), 或“自动增量的事务ID”实现“事务一致性”。MVCC可以确保每个事务(T)通常不必“读等待”数据库对象(P)。这通过对象有多个版本,每个版本有创建时间戳 与废止时间戳 (WTS)做到的。
MVCC 可以无锁实现(基于时间戳),也可以使用锁, 或者混合使用锁和时间戳.
PSQL 默认会锁定被 UPDATE 影响的行. 如下,两个会话的事务同时修改同一行,另一个事务将进入等待.
1 Mastering PostgreSQL 9.6
事务
事务基础
事务中的错误处理
end,commit
也是 执行rollback
操作.事务的保存点
在上面事务逻辑中,事务中出错之后会导致所有执行都回滚. 如果要允许部分成功.则需要使用保存点.
savepoint <savepoint_name>
rollback to savepoint <savepoint_name>
release savepoint <savepoint_name>
.事务性 DDL
对于 DDL 支持事务是 PSQL 的独有强大特性. 一般的 DDL 命令都支持事务.(drop database,create tablespace,drop tablespace 操作除外)
事务隔离级别
先看一个例子.
左边的事务受其他提交的事务的影响,两次返回的和不一样.这就是因为 PSQL 默认的事务的隔离级别是读提交. 要想左边的事务,一直读到的是同样的值可以采用可重复读的隔离级别. 示例如下:
PSQL 支持的隔离级别
read committed
读提交. (默认隔离级别).repeatable read
可重复读. (冻结数据快照)read uncommited
读未提交.(PSQL 将其映射成 read committed,只是标准中有这一级别)serializable
可序列化(可串行化,Serializable Snapshot Isolation (SSI)). 除非对数据库引擎有很深理解 ,否则一般不建议使用.隔离级别对应常见的一些问题.
不可重复读 VS 幻读
所以可以这么理解,一般另一个事务中的
update
会可能导致不可重复读 (update 修改了数据.) 而insert
和delete
语句可能导致幻读(insert,delete 修改了数据集). 不过update
和delete
也会生成不可重复读,比如一个统计语句的查询数据结果就会受到 insert,delete 语句的影响.默认隔离级别读提交的数据可见性规则
如下图,删除语句的执行结果为空. 因为.
PSQL 多版本并发控制的要读提交是在每一个命令开始时,就创建一个数据的新的快照(包含此刻所有已经提交的事务的数据更新).当前事务的后续语句能看到其他情况下并发提交的事务的变更.
具体来说, delete 开始执行时,收集了匹配的行,但是同时也知道其他正在进行中的事务会影响到匹配的行, delete 将其放到 可能会变更的行的列表. 当其他事务都提交了之后, delete 会重新评估可能会变更列表里的行.如果对应已经被删除或者已经不匹配则忽略. 也就是说 delete 最终看到的是提交之后的数据版本.
对于
select for update
或select for share
,锁定和返回给用户的数据也是更新后的版本.锁
并发场景下的数据一致性,乐观锁,悲观锁与 MVCC
乐观锁 (OCC,Optimistic Concurrency Control,乐观并发控制)
乐观并发控制的事务包括3个阶段:
悲观锁 (PCC, Pessimistic Concurrency Control,悲观并发控制)
适用写多读少的情况.
多版本并发控制 (MVCC,Multiversion Concurrency Control)
PSQL 中的并发控制采用 (MVCC), MVCC 的一大优点就是读写互相不阻塞.
MVCC 可以无锁实现(基于时间戳),也可以使用锁, 或者混合使用锁和时间戳.
默认的更新锁
PSQL 默认会锁定被 UPDATE 影响的行. 如下,两个会话的事务同时修改同一行,另一个事务将进入等待.
参考
1 Mastering PostgreSQL 9.6