数据库悲观锁与乐观锁的理解和实现
Posted 一只当归
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库悲观锁与乐观锁的理解和实现相关的知识,希望对你有一定的参考价值。
什么是乐观锁和悲观锁?这其实是人们定义出的一种思想,可以对应为在生活中乐观的人和悲观的人。乐观锁总是相信最好的情况,去相信别人不会修改自己的数据,在每次取数据的时候都不会上锁,因此比较适用于读多写少的情况。而悲观锁恰恰相反,总是担心别人会去修改自己的数据,所以在每一次取数据时都会上锁,比较适用于写多读少的情况。
- 悲观锁
首先我们来了解一下悲观锁,悲观锁认为被它保护的数据不安全的,随时都有可能变动,一个进程或线程拿到悲观锁后,其他的进程或线程都不能对该数据进行修改,只能等待锁被释放,下一个拿到锁的进程才能进行修改。悲观锁是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会产生额外的开销,还有增加产生死锁的机会。另外还会降低并行性,一个进程或线程如果锁定了某个数据,其他进程或线程就必须等待其处理完才可以处理那个数据。
悲观锁的实现:
1.传统的关系型数据库使用这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
2.Java 里面的 synchronized和ReentrantLock独占锁也属于悲观锁。 - 乐观锁
乐观锁的乐观是相对于悲观锁而言的,乐观锁的乐观体现在,它认为数据的变动不会太频繁,因此它允许多个进程或线程同时对数据进行访问和修改。但是乐观锁也不是毫无安全性可言,乐观锁会在数据进行提交更新的时候去判断别人有没有去修改这个数据。如果发现出现了冲突,则返回给用户错误的信息,让用户重新去操作。乐观锁机制采取了更宽松的加锁机制,适用于读操作多的情况,可以提高程序的吞吐量,不会产生死锁的情况。
乐观锁的实现:
CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。
版本号控制:通常是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会+1。当线程A要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。
乐观锁与悲观锁的对比与选择:
1.响应效率:如果需要高响应速度,推荐使用乐观锁,成功就执行,不成功就失败,不需要等待其他进程去释放锁。
2.冲突频率:如果冲突频率高,推荐使用悲观锁,保证成功率。冲突频率高的话,选择乐观锁会需要多次重试才能成功,代价较大。
3.重试代价:如果重试代价大,推荐使用悲观锁。悲观锁依赖数据库锁,虽然效率较低,但失败的概率也比较低。
4.还有一点区别是,使用乐观锁如果有人在你之前更新了数据,那么你的更新是被拒绝的,返回至用户重新操作,而悲观锁则会等待前一个进程把数据更新完成,再去进行操作。
以上是关于数据库悲观锁与乐观锁的理解和实现的主要内容,如果未能解决你的问题,请参考以下文章