Repeatable read isolation level 只能看见transaction开始前提交的数据;看不见未提交的数据和在当前transaction执行当中,其他并发transaction提交的数据。在同一个transaction内,当前命名可以看到上一条语句执行的结果。在PostgreSQL里,repeatable read解决了出serialization anomalies外所有的缺陷。在标准里面,只说了具体数据库的实现中各个的isolation level最少要处理哪些缺陷,没说不能多处理缺陷。
快照在transaction的第一条 non-transaction-control-statement产生,而不是当前sql语句。因此,在同一个transaction中,连续的select语句可以看到相同的数据。比如,在自己的transaction执行当中,是看不到其他transaction提交的数据。
sex | name |
male | 李雷 |
female | 韩梅梅 |
Repeatable Read transaction1 | Repeatable Read transaction2 |
Begin: | Begin: |
Select * from user where sex=’male’; 查出:李雷 |
|
| Insert into user (‘Jack’, ‘male’) |
| Commit; 提交以后,transaction1 可见Jack。不提交就不可以,所以叫read committed |
Select * from user where sex=’male’; 查出:李雷,看不见Jack |
|
如果要用这个level,应用需要使用重试transaction机制,来应对serialization failures
Repeatable Read transaction1 | Repeatable Read transaction2 |
Begin: | Begin: |
| Update user set name=’Dear’+name where sex=’male’ |
Update user set name=’Mr.’+name where sex=’male’;
| Commit; 假设在transaction1阻塞后执行的commit,。 |
|
|
以上逻辑同样适用于delete,select for update 和 select for share |
|
|
|
UPDATE, DELETE, SELECT FOR UPDATE, and SELECT FOR SHARE在查询目标数据方面和select的情况一样:从transaction开始的时候,生成的数据库快照里找。如果在transaction执行中,被查出来待修改的数据被其他并发transaction修改提交或者回滚了,相应的当前transaction就会回滚或者继续执行。
报错信息:ERROR: could not serialize access due to concurrent update
Repeatable read transaction 不能修改或者锁被其他transaction修改的行。
当应用收到以上异常,应该回滚transaction并重新发起。Transaction会重新获取快照,数据就会保持一致性。
只有更新数据的transaction需要重试,只读的transaction不会有serialization conflicts.
Transaction1 | Transaction2 |
Begin; 获取当前数据库快照 | Begin; 获取当前数据库快照 |
| Update user set name=’张三’ where id=1 |
Select * from user where id=1 这条数据已经被transaction2修改,等待transaction2提交 |
|
| Commit; |
Id=1这条记录已被修改,事务回滚 |
|