数据库隔离之 serializable transaction isolation

The Serialization isolation level 是最严格的隔离级别。对所有提交的transactions, 这个level模仿了序列化的transaction执行; 就像并发的transaction是一个接着一个执行的,序列化地,而不是并发地。使用serializable isolation level,应用应该做好重试机制,应对可能serialization failures。Serializable isolation level的内部机制和repeatable read相似,除了serialization会监控查询条件(where 语句),这些查询条件可能导致数据不一致。这个监控不会带来比repeatable read 更多的阻塞,会带来些负载, 会查验where语句是否会造成serialization anomaly以及serialization failure.

 

Table: mytab

class | value

-------+-------

     1 |    10

     1 |    20

     2 |   100

     2 |   200

 

SELECT SUM(value) FROM mytab WHERE class = 1;

Serializable Transaction1 执行以上语句, 再把结果30和class=2新插入一列。

 

SELECT SUM(value) FROM mytab WHERE class = 2;

Serializable Transaction2 执行以上语句, 再把结果300和class=1新插入一列。

 

两个transaction执行完语句后同时commit。先提交的那个transaction会成功,后提交的那个transaction里,select的值已经变了,会抛出异常:

 

ERROR:  could not serialize access due to read/write dependencies among transactions

Serializable Transaction 1

Serializable Transaction 2

begin

begin

SELECT SUM(value) FROM mytab WHERE class = 1;

SELECT SUM(value) FROM mytab WHERE class = 2;

Insert mytab (30, 2)

Insert mytab (300, 1)

Commit;

 

 

Commit;

 

 

 

Transaction1 会成功,transaction 2会失败。在transaction 2中,select语句之前查出的是300,transaction1提交一个,应该是330。如果transaction1 和transaction2顺序执行,transaction2的select查出的应该是330,所以transaction 2抛出异常回滚了。

 

使用serializable transactions时,只读transaction也可能被回滚,只要在这个transaction提交的时候,它读的数据已经过期了。Deferrable read-only transaction例外。应用不能依赖于被回滚的transaction查出来的数据;应用应该retry回滚的事务。

spring 环境下 

@Retryable(

value = {SQLException.class},

maxAttempt=2,

backoff=@Backoff(delay=5000)

)

void myService() throws SQLException{

... ...

}

@Recover

若retry仍然不成功,调用@Recover注解的方法

PostgreSQL使用predicate locking 来保证serializable transactions的serialiability。有些写的操作,会导致其他transaction里读的操作过期,这个predicate locking 帮助确保让这个写操作在度的操作前面。Predict locking不会造成阻塞或者死锁。Predicate是用来识别和标识并发serializable transactions 之间的依赖,这些transactions的某些组合会导致serialization anomalies。Read committed 和repeatable read transaction要保证一张表的数据一致性,需要锁表;或者使用select for update, 这会阻塞其他transaction 以及造成 disk access。

 

Serializable transactions 用简单的方式满足了数据一致性。一堆并发的serializable transactions提交的结果,和这些transaction挨个执行的结果是一样的;也就是说如果单个transaction被认为是对的,那么把它放到并发的环境下也不会错。需要有一个通用的方式来处理serialization failures, 因为这种异常很难预测。对read/write dependencies的监控和重启transaction都要耗费资源,但是相对于select for update 以及其他锁造成的阻塞的开销,serilizable transactions 是the best performance choice.

 

Serializable transaction会有些问题,这些问题不会再真正序列化的执行中发生。所有serializable transactions在插入记录前,用select做验证,可以避免这种错误。

 

为了在使用serializable transactions 时,达到最好的性能,我们应该考虑:

可能的话,把transaction 设置为READ-ONLY

使用连接池,并控制连接的数量。在高并发的系统中,这点尤为重要。

别在一个transaction里放太多

别让idle in transaction的时间太长了。

在serialization transactions的保护下,确认select for update语句可以删除,就删除。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值