定义
数据库托马斯写入法则Thomas Write Rule,保证了数据库协议的序列化顺序,说得直白一点是多线程或者并发控制机制,保证数据的正确。数据库常见的序列化顺序算法有两个:一是时间排序算法Basic Timestamp Ordering Algorithm;二是托马斯写入法则,或叫托马斯写规则Thomas Write Rule。
托马斯写规则,有几个特殊的符号定义。首先,TS代表时间戳timestamp,R代表读read,T代表写write。托马斯写规则定义了以下三条规则:
- TS(T) < R_TS(X),即事务T的时间戳小于读取X的时间戳,也就是数据库在接收请求时,发现了一个并发,但是事务先于读取,那么读取的时候就会读到事务T修改后的数据,这个时候事务要回滚,并且读操作要拒绝。对应Java的场景就是写锁是不允许读的。
- TS(T) < W_TS(X),即事务T的时间戳小于写X的时间戳,也就是数据库在接收请求时,发现了一个并发,但是事务先于写入,那么写入的时候就会修改T修改后的数据,这时写操作不执行,但是事务正常执行。这是托马斯写法则特有的过期写(Outdated or Obsolete Writes)场景
- 如果上面两种情况都没发生,那么执行事务,并且把X的修改时间设置为事务的执行时间。
可以用一张表总结一下:
前一步 | 读 | 写 |
---|---|---|
后一步读 | 允许执行 | 不允许读,写事务回滚 |
后一步写 | 不允许写,允许读 | 前一个写允许,后一个写不允许(特殊的过期写场景) |
基本时间戳排序
基本时间戳排序,英文为Timestamp Ordering Protocol,简称TO协议,是给所有的操作一个时间戳,时间戳一般有两种,一个是系统当前时间,毫秒之类的,另一个是递增的时间戳。TO协议定义了两种场景,事务Ti在读和事务Ti在写。并且所有成功的操作都需要更新时间戳。
当事务Ti在读x时,它的时间戳记为TS(Ti),另外一个写x的事务时间戳,记为 W_TS(X),分以下场景:
- W_TS(X) >TS(Ti) ,那么这个写操作被拒绝执行,意思是如果另一个事务先读取了x,但是还没提交,其他后续事务不允许写。
- W_TS(X) <= TS(Ti),那么这个写操作被执行,意思是如果另一个事务先写了,后续事务是可以读的,这样读到的是写之后的结果。
当事务Ti在写x时,它的时间戳记为TS(Ti),另外一个写x的事务时间戳,记为 W_TS(X),读操作记为R_TS(X),也分两种场景:
- TS(Ti) < R_TS(X),这个读操作被拒绝,意思是不允许后续事务读其他事务已提交的数据。
- TS(Ti) < W_TS(X),那么后面的写操作不被允许,并且前一个事务Ti也要回滚。
可以用一张表总结一下:
前一步 | 读 | 写 |
---|---|---|
后一步读 | 允许执行 | 不允许读 |
后一步写 | 不允许写 | 写操作拒绝,前一个事务回滚 |
二者对比
注意,无论那个并发协议,前提都是两个事务在时间上存在交叉。假如是单线程,事务串行执行的,这两个协议都是允许的,无论读写顺序是什么。我用一张表总结下两个事务之间的并发场景:
场景 | 时间戳协议 | 托马斯写法则 |
---|---|---|
双读 | 允许 | 允许 |
读先写后 | 不允许写 | 不允许写 |
写先读后 | 不允许读 | 不允许读,前一个回滚 |
双写 | 前一个回滚,后一个不允许 | 前一个执行,后一个不允许 |
若有疏漏之处,或者不同意见请在评论区告诉我。