丢失更新的定义:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其他事务的存在。最后的更新将覆盖由其他事务所做的更新,这将导致数据丢失。
典型事务序列是:
begin Transaction;
select col_value into :var_col_value from tableA where keyid=:keyid;
......
var_col_new_value=var_col_value+1
update tableA set col_value=:var_col_new_value where keyid=:keyid;
commit;
丢失分析:
- update更新依赖于select选定的行
- 更新的值依赖于select的结果
- 有多个事务存在,另外一个事务的select可能出现在:
- 本事务的select之后,update之前
- 如果允许读,读到的依然是var_col_value,必然发生丢失
- 本事务的update之后,commit之前
- 如果允许脏读,读到的是var_col_new_value,但是存在脏写,依然不安全
- 如果允许读,但不是脏读,读到的依然是var_col_value,必然发生丢失
- 本事务的commit之后
- 读到的是var_col_new_value,不会丢失
- 本事务的select之后,update之前
防止丢失:
- 针对简单类型及逻辑:
- 更改update SQL语句为累加,即
- update tableA set col_value=col_value+1 where keyid=:keyid;
- 不能改变SQL时,需要把select延迟到commit之后
- 提升事务隔离级别
- 可重复读Repeatable read
- 可序列化Serializable
- 提升事务隔离级别