丢失更新及其解决办法
丢失更新:多个事务对同一条记录进行了操作,后提交的事务将先提交的事务操作覆盖了。
解决丢失更新可以采用两种方式:
-
悲观锁 (假设丢失更新一定会发生 )
利用数据库内部锁机制,管理事务
数据库提供的锁机制- 共享锁: 阻止其他事务写表(即其他事务不能write,可以read)
select * from table lock in share mode(读锁、共享锁)
- 排它锁: 阻止其他事务读、写该表
select * from table for update ( 写锁、排它锁 )
数据库默认添加排它锁
- 共享锁: 阻止其他事务写表(即其他事务不能write,可以read)
-
乐观锁(假设丢失更新不会发生)
采用程序中添加版本字段解决丢失更新问题create table product ( id int, name varchar(20), updatetime timestamp );
事务操作时:
- 先查询获得 queryTimestamp
update product set name='洗衣机' where id = 1 and timestamp=queryTimestamp
;
数据表添加版本字段,每次修改过记录后,版本字段都会更新,如果读取的版本字段 ,与修改时版本字段不一致,说明别人进行修改过数据 (更新失败,重新尝试)
乐观锁性能优于悲观锁,悲观锁将数据锁定,其他事务可能一直处于等待状态。乐观锁 其他事务可以读,写的话要么出错,要么成功,不会一直等待。
Hibernate 解决
- 悲观锁
例: 设置排他锁session.get(Street.class, 1,LockMode.PESSIMISTIC_READ); // 悲观读(共享锁) session.get(Street.class, 1,LockMode.PESSIMISTIC_WRITE); //悲观写 (排他锁)
- 乐观锁
- 在对象中设置版本字段
private Integer version;
- 在映射文件中 id 标签后配置版本
<version name="version"/> // name= version 和对象中的属性名相同
配置后,在事务中就会自动维护版本号