乐观锁( Optimistic Locking):顾名思义,对加锁持有一种乐观的态度,即先进行业务操做,不到最后一步不进行加锁,"乐观"的认为加锁必定会成功的,在最后一步更新数据的时候再进行加锁。sql
悲观锁(Pessimistic Lock):正如其名字同样,悲观锁对数据加锁持有一种悲观的态度。所以,在整个数据处理过程当中,将数据处于锁定状态。悲观锁的实现,每每依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,不然,即便在本系统中实现了加锁机制,也没法保证外部系统不会修改数据)。数据库
乐观锁:spa
version方式:通常是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,不然重试更新操做,直到更新成功。
sql实现代码:线程
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
CAS操做方式:即compare and swap 或者 compare and set,
涉及到三个操做数,数据所在的内存值,预期值,新值。当须要更新时,判断当前内存值与以前
取到的值是否相等,若相等,则用新值更新,若失败则重试,通常状况下是一个自旋操做,即不
断的重试。code
悲观锁:blog
是由数据库本身实现的,要用的时候,咱们直接调用数据库的相关语句就能够了(原理:共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程),如行锁、读锁和写锁等,都是在操做以前加锁,在Java中,synchronized的思想也是悲观锁。内存
乐观锁:资源
比较适合读取操做比较频繁的场景,若是出现大量的写入操做,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层须要不断的从新获取数据,这样会增长大量的查询操做,下降了系统的吞吐量。io
悲观锁:table
比较适合写入操做比较频繁的场景,若是出现大量的读取操做,每次读取的时候都会进行加锁,这样会增长大量的锁的开销,下降了系统的吞吐量。
乐观锁的特色先进行业务操做,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,所以在进行完业务操做须要实际更新数据的最后一步再去拿一下锁就好。
悲观锁的特色是先获取锁,再进行业务操做,即“悲观”的认为获取锁是很是有可能失败的,所以要先确保获取锁成功再进行业务操做。一般所说的“一锁二查三更新”即指的是使用悲观锁。
简而言之记得一句话:读取频繁使用乐观锁,写入频繁使用悲观锁。乐观锁不能解决脏读的问题。