数据库系列(三)之 锁

锁的意义

     数据库中有很多‘锁’的使用。怎么合理并灵活的应用是一个值得讨论深究的问题。

     锁为何而存在?为了在同一时间内,只能处理一种请求。而避免导致的数据错乱。例如商城中,库存的扣减;金融系统中金钱的转账。

     在耳熟能详的商城中,库存扣减有很多种方法来处理,其中数据库锁是很大众的一种方式。在应用程序中,存在着多个用户同一时间购买商品的可能。这时候就要扣减库存。怎么保证库存扣减的正确性呢?答案就是用锁来做限制。

     例如商品只剩下库存数量为1。这时候商品有多人在抢,那么只能有一个人购买成功。否则扣减过多而导致业务销售的‘售后’问题。

 

乐观锁与悲观锁

悲观锁                                                                                              

     悲观锁是指同时只有一个才能处理锁的内容,其它都需要等待排队。悲观锁是建议在数据库层面。

     在数据库层面,实现锁可以有表锁、页锁、行锁。它们各自有优缺点。

表锁                        

     表锁顾名思义,锁住整张表。

     表锁的特点:开销小,加锁快;不会出现死锁;锁冲突概率高,并发度低。

SqlServer

     sqlsever中加表锁很简单,在select最后加相应的语句即可:

共享锁:SELECT * FROM table WITH (HOLDLOCK)

排他锁:SELECT * FROM table WITH (TABLOCKX)

Postgresql

     使用表锁的格式为:LOCK [ TABLE ] [ ONLY ] name [ * ] [, ...] [ IN lockmode MODE ] [ NOWAIT ]

页锁                        

     页锁一般比较少用。

     页锁的特点:开销、加锁速度、并发度在于表锁与行锁之间;会出现死锁。

行锁                        

     行锁是使用较多的一种。

     行锁的特点:开销大,加锁慢;会出现死锁;锁定粒度小;索冲突概率低,并发度高。

     在大部分的数据库中,执行delete、insert、update语句都会加锁,delete、insert一般都是行锁。update时看是否存在索引为查询条件,如果存在则行锁,不存在则表锁。

Mysql

     在Mysql中,不同的引擎支持的表锁是不同的。最广泛使用的引擎是InnoDB,也是作为各大云厂商的默认使用。InnoDB是支持行锁、表锁。MyISAM引擎支持表锁。BDB引擎支持表锁、页锁。

     这里只介绍InnoDB引擎,这也是使用最多的引擎。

     在mysql中,表锁的语句如下:

共享锁:SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。

排他锁:SELECT * FROM table_name WHERE ... FOR UPDATE。

     共享锁与排他锁这里不介绍,后面会详细说明。

     表锁没有固定的语句,使用的时候会根据索引来确定使用表锁还是行锁。这意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。

SqlServer

     sqlserver的行级锁比较简单,在表名后面加ROWLOCK即可:

SELECT * FROM table ROWLOCK WHERE id=xxx

Postgresql

     因Json的原因,Postgresql越来越流行。其使用行锁的关键字为:FOR UPDATE、FOR NO KEY UPDATE、FOR SHARE、FOR KEY SHARE。

乐观锁                                                                                               

     在悲观锁中,之所以成为悲观,因为都需要等待的操作。有没有一种无需等待、相互争抢的锁呢?答案是有的,与之相反,称为乐观锁。

     乐观锁不是在数据库层面做的,在程序上写。怎么实现乐观锁呢?通常在表中加个字段,版本号version或当期时间date都可以。

     举个version版本号的例子,例如当期的version=1。

     语句一般为:update table set inventory=1, version=version+1 where version=1 and id=xxx

     这样就实现了乐观锁的模式。因为他们都互相争抢,谁抢到了就返回修改条数为1,没有抢到为0。其实其中也使用到了数据库中的悲观锁。因为在update时,使用了索引,是锁行的。但是这种明显是比全悲观锁的形式是快的。

     乐观锁的特点:速度快、但增加数据库CPU。

 

排它锁与共享锁

     排他锁及共享锁其实很简单。

     排它锁是指在锁住期间,不能对相应的数据做查询、增加、修改、删除操作。排他锁保证了其他事物不能读,用于行级。

     共享锁是指在锁住期间,能对相应的数据做查询操作,不能做增加、修改、删除操作。保证了其他事务不能写,用于表级。

 

可以关注本人的公众号,多年经验的原创文章共享给大家。

你可能感兴趣的:(数据库系列(三)之 锁)