数据库锁
什么是锁?
当多个用户并发操作数据库,为保证数据的一致性而形成的一把钥匙。
怎么上锁?
常用:select 。。。。for update。
一般在mysql 使用 innoDb 在使用索引的情况下会进行行锁,但是在没有使用的索引的情况下则会进行表锁。
怎么使用for update?
那些需要业务层面数据独占时,可以考虑使用for update。
场景上,比如火车票订票,在屏幕上显示有票,而真正进行出票时,需要重新确定一下这个数据没有被其他客户端修改。所以,在这个确认过程中,可以使用for update。
锁的分类?
从数据库系统角度分为三种:排他锁、共享锁、更新锁。
从程序员角度分为两种:一种是悲观锁,一种乐观锁。
悲观锁:顾名思义 ,就是很悲观,每次去拿数据都担心 这个数据已经被修改过,所以每次去拿数据前就会去上锁,这样别人每次去拿都会被阻塞知道他解锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据都觉得别人没有修改过,所以去拿数据源的时候不会上锁,但是每次使用数据的时候会校验期间有没有人使用过这个数据,一般通过版本号机制。
乐观锁用于多读的场景,提高吞吐量。
版本号机制:版本号(记为version):就是给数据增加一个版本标识,在数据库上就是表中增加一个version字段,每次更新把这个字段加1,读取数据的时候把version读出来,更新的时候比较version,如果还是开始读取的version就可以更新了,如果现在的version比老的version大,说明有其他事务更新了该数据,并增加了版本号,这时候得到一个无法更新的通知,用户自行根据这个通知来决定怎么处理,比如重新开始一遍。这里的关键是判断version和更新两个动作需要作为一个原子单元执行,否则在你判断可以更新以后正式更新之前有别的事务修改了version,这个时候你再去更新就可能会覆盖前一个事务做的更新,造成第二类丢失更新,所以你可以使用update … where … and version=”old version”这样的语句,根据返回结果是0还是非0来得到通知,如果是0说明更新没有成功,因为version被改了,如果返回非0说明更新成功。
排他锁(Exclusive Lock)
X锁,也叫写锁,表示对数据进行写操作。如果一个事务对对象加了排他锁,其他事务就不能再给它加任何锁了。(某个顾客把试衣间从里面反锁了,其他顾客想要使用这个试衣间,就只有等待锁从里面打开了。)
产生排他锁的SQL语句如下:select * from ad_plan for update;
避免死锁的方法
一次封锁法:每个进程(事务)将所有要使用的数据全部加锁,否则,就不能继续执行;
顺序封锁法:预先对数据对象规定一个封锁顺序,所有进程(事务)都按这个顺序加锁;
银行家算法:保证进程处于安全进程序列。
有助于最大限度地降低死锁的方法
按同一顺序访问对象;
避免事务中的用户交互;
保持事务简短并在一个批处理中;
使用低隔离级别。