大家以前可能都听说或者了解过数据库锁的相关知识,为什么需要锁呢,锁又是什么呢?下面我会详细的给大家讲一讲。
数据库锁出现的目的:处理并发问题
并发问题是什么?
我们都知道数据库可能会被同时大量访问,这时假如第一个线程访问并修改了我们的数据库某个字段,第二个线程访问也修改了这个字段,那么就造成了同时访问问题,这时由于他们都修改了数据库,那么就会造成脏数据问题,第一个线程访问并修改的数据被覆盖掉了。
为了防止这种情况发生,我们就发明这个技术,当一个事务访问数据库时,锁会将所修改的表锁起来,另一个事务没有办法同时对这个表进行修改,这时就达到了我们的目的,不会产生脏数据。
那么锁的分类是什么呢?如下所示:
一.乐观锁:
乐观锁是指我们假设数据一般情况下不会造成冲突,当要进行数据提交更新的时候,我们才会对数据进行检测,然后将结果返回给用户,让用户决定该如何去处理。乐观锁并不是数据库的一种额外机制,它只是依靠数据本身来对数据是否修改来进行了检测判断。
乐观锁实现:
1.依靠原有字段来实现乐观锁:比如有个字段是商品库存,事务一先查询库存数,查出来是3,这时候事务二对商品库存进行了修改,变成了2,这时候事务一打算更新数据,再次进行查询了商品库存,发现跟它取数据的时候的库存数不一样,这时候就会返回给提交人一条信息,告诉他已经发生改变,是否继续执行原有修改操作。
2.依靠原有字段不会改变表结构,但是会有一种严重的ABA问题,就是说刚才情境下事务二将其变为2后再改成了3,这种情况下并不是说数据就没有发生修改,这个过程其实是有问题的。那我们要如何处理这种情况呢?我们可以多加一个版本字段version,每当修改一次数据,这个字段会自动加一,这样就很合理了,不会出现刚才的ABA问题。但是其会改变表结构,所以还是要均衡考虑。当然,时间戳也是这种情况下的一种体现,其天然的自增性使其也非常合适。
但是乐观锁存在一个高并发下的问题,当数据处于高并发情况下,比如淘宝这种网站,乐观锁会使事务频繁操作失败,这对于用户来说一点也不友好,相对于悲观锁那种只要加上锁基本就能更新成功来说,乐观锁失败概率是很高的。当然我们也会有一定手段可以来降低失败概率,比如优化SQL,使用库存递减等方式来实现。
二.悲观锁:
悲观锁为什么悲观?因为它实际上是一种"先取锁再访问"的方式,为什么这样呢?因为它假设我每次访问数据时都会遇到别的事务来对我取得数据产生了影响,所以我需要提前加锁,来保证别的事务对我操作的数据不能产生任何影响。
共享锁(S锁)
共享锁是指多个事务可以对一个共享页上锁,但是只能读共享页中的内容,任何事务都不能修改共享页中的内容,在该页被读取完毕时,S锁立刻被释放。
排它锁(X锁)
排他锁只能被一个数据库事务封锁此页,其他的事务无法再对此页上锁,相当于事务独占了此数据页。
更新锁(U锁)
更新锁是对共享锁的改进,其用于来预定封锁数据页,一般来说,想要修改某个数据,会先给数据页加上S锁,然后等待别的事务将所有的S锁释放,然后自己升级为X锁,但是这样有一个问题,假如多个事务同时对一个资源加上了 S锁,都需要修改数据,那么他们都要升级为X锁,所以他们都在等待对方先将S锁释放,这样就造成了“死锁”问题,所以为了解决这个问题,就产生了U锁,U锁可以和S锁共存,但是它们共存时只有U锁能升级为X锁,S锁在它面前只能选择释放资源,并且一个资源同时只能存在一把U锁,这样就完美解决了死锁问题。
那悲观锁的优点和缺点在哪里呢?
优点:
优点肯定是非常明显的,悲观锁确保了数据的安全性,因为同一个数据同时只能有一个事务在进行操作,所以其数据非常安全。
缺点:
悲观锁是数据库的一种机制,所以肯定会产生额外的性能开销,并且会增加产生死锁的机会,并且会降低并行性,因为同一个数据在同时只能有一个事务在进行数据处理。
应用场景:
1.乐观锁经常使用,特别是在高并发等场景下。
2.悲观锁使用的很少,在必须保护数据安全且并发较少的情况下用到,不过现在生产环境已经较少用到了。
                    
                
                
            
        
浙公网安备 33010602011771号