锁机制(悲观锁乐观锁)

锁概念

当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取统一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。所以,锁主要用于处理并发问题

从数据库系统角度分为三种:排他锁、共享锁、更新锁。   
从程序员角度分为两种:一种是悲观锁、一种乐观锁。

悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。

传统的关系数据库里用到了很多这种锁机制,比如按使用性质划分的读锁、写锁和按作用范围划分的行锁、表锁。

对于可能冲突的并发操作,以串行的方式取代并发执行,因而它也是一种悲观并发控制。

1、共享锁(事务只能读)

共享锁(Shared lock)(S锁)又称为读锁,若事务T对像A加上S锁,则事务T只能读A;其他事务只能对A加S锁,而不能加X锁,直到T释放A上的S锁。。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改

2、排他锁

排他锁(X锁)又称为写锁,若事务T对数据对象A加上X锁,则指允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。

3、表锁

每次操作锁住整张表,开销小,加锁快,锁粒度大,发生锁冲突的概率高,并发度最小

4、行锁

每次操作锁住一行数据,开销大,加锁慢,锁粒度小,发生锁冲突的概率最低,并发度最高。
数据库能够确定那些行需要锁的情况下使用行锁,如果不知道会影响那行的时候会使用表锁。

乐观锁
(没有用锁,使用了一些比较,如果比较符合自己的想法,就交换或执行)

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断以下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现

允许可能冲突的操作并发执行 是一种乐观的并发策略

1、版本号机制

一般是在数据表中加入一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version指会加一。当线程A要重新更新数据值时,在读取数据的时候也会读取version值,在提交更新时,若刚才读取到的version值与当前数据库中的version值相等才更新,否则重新更新操作,直到更新成功

CAS算法

CAS 即compare and swap(比较并交换),是一种有名的无锁算法,在不适用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量同步,所以也叫非阻塞同步。CAS算法涉及到三个操作数:

1、要更新的变量V
2、预期的值E
3、新值N

仅当V值等于E值时,才会将V的值设置为N,否则说明都不做。最后CAS返回当前V的值。CAS算法需要你额外给出一个期望值,也就是你认为现在变量应该是是样子的,如果变量不是你想象的样子,就说明已经被别人修改过,就重新读取,再次尝试修改即可。

ABA问题?

 因为CAS需要在操作值得时候检查下值有没有发生变化,如果没有发生变化则更新,但如果一个值原来是A,变成了B,由变成了A,那么使用CAS进行检查时就会误以为它的值没有发生变化,这个问题称为ABA问题。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A就会变成1A-2B-3A,以此来防止不恰当的写入。

乐观锁和悲观锁的适用场景

乐观锁适用于写比较少(多读场景) ,即冲突真得很少发生得时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行重试,这样反倒是降低了性能,

所以一般 多写的场景下用悲观锁比较合适

数据库中的事务根据不同的应用场景使用不同类型的锁
写较小少用乐观锁,写较多用悲观锁

事务的本质就是一个函数方法,里面有多个sql执行语句。只不过这个方法是(隔离性)独立执行的,原子性的(一定执行完的 不然回滚)
所以事务中的多个sql执行语句能够串行执行下来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值