最初,接触到事务中的锁概念是从数据库原理开始的。其中,锁相关的类型概念也比较多,如共享锁,排他锁,意向锁,悲观锁,乐观锁等等。
一 数据库事务的概念和特性:
1 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
2 事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。
二 四大问题
1、脏读
某个事务读取的数据是另一个事务正在处理的数据。而另一个事务可能会回滚,造成第一个事务读取的数据是错误的。
2、不可重复读
在一个事务里两次读入数据,但另一个事务已经更改了第一个事务涉及到的数据,造成第一个事务读入旧数据。
3、幻读
幻读是指当事务不是独立执行时发生的一种现象。例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
4、更新丢失
多个事务同时读取某一数据,一个事务成功处理好了数据,被另一个事务写回原值,造成第一个事务更新丢失。
三 锁
1 排他锁
独占锁也叫排他锁,适用于修改数据的场合。它所锁定的资源,其他事务不能读取也不能修改。
2 共享锁
共享锁用于读取数据操作,它是非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它。
3 意向锁
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。
由两种基本的锁类型(S锁、X 锁),可以自然地派生出两种意向锁:
意向共享锁(Intent Share Lock,简称 IS 锁):如果要对一个数据库对象加S锁,首先要对其上级结点加IS 锁,表示它的后裔结点拟(意向)加 S锁;
意向排它锁(Intent Exclusive Lock,简称 IX 锁):如果要对一个数据库对象加X 锁,首先要对其上级结点加 IX锁,表示它的后裔结点拟(意向)加X 锁。
引申出一种锁类型:
共享意向排它锁(Shared Intent Exclusive Lock,简称 SIX 锁) :如果对一个数据库对象加 SIX 锁,表示对它加 S 锁,再加 IX 锁,即 SIX=S+IX。例如:事务对某个表加 SIX 锁,则表示该事务要读整个表(所以要对该表加S 锁),同时会更新个别行(所以要对该表加 IX锁)。
4 悲观锁
悲观锁(Pessimistic Lock),每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
5 乐观锁
乐观锁(Optimistic Lock),每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
注:
悲观锁:利用数据库本身的锁机制实现。通过上面对数据库锁的了解,可以根据具体业务情况综合使用事务隔离级别与合理的手工指定锁的方式比如降低锁的粒度等减少并发等待。
乐观锁:利用程序处理并发。原理都比较好理解,基本一看即懂。方式大概有以下3种
对记录加版本号.
对记录加时间戳.
对将要更新的数据进行提前读取、事后对比。