悲观锁貌似没法解决更新丢失的问题。见下面的例子,两个用户张三,李四,他们两人可以更新同一条数据库记录。假设记录为(sex,age) = (‘male’, 25)。在张三的查询和修改的时间间隔内,李四更新了记录,而张三对这种情况不知情,最后导致李四的更新丢失了。无论加不加悲观锁,都解决不了这种问题。我的问题是
1)对于这种并发写冲突,是不是只能用乐观锁(给表加一个版本号字段)来防止更新丢失?
2)那select … for update这种悲观锁在什么场景下使用,悲观锁的使用应该是为了解决并发写冲突,但貌似它又不能解决更新丢失问题,感觉有点鸡肋啊,亦或是我理解有误.
有一篇相关文章,参见http://www.douban.com/note/204830640/
回答
张三和李四的例子中实际上没有加锁。这是事务的问题。
李四在张三还没执行修改之前就把记录给修改了,导致其修改被张三覆盖,所以更新丢失。这个问题的根本原因是事务没有进行隔离(可以搜索一下事务的ACID分别是什么)。张三的修改操作和李四的修改操作分为两个不同的事务,事务之间应该具有隔离性(ACID中的I)。
实现隔离性的方法是加锁,又分为悲观锁和乐观锁。
当张三想要修改记录时,首先对这条记录加锁,这样在张三持有锁的期间,李四就修改不了这条数据了,张三修改完成后释放锁,李四再获得这个锁,然后修改记录,释放锁。为什么称为悲观锁呢,主要是,每个想要修改记录的人都“悲观地”认为别人会来并发修改这条数据,所以要先加锁。
你这个问题是事务的问题,不是锁的问题。