悲观锁和乐观锁
悲观锁
即对一切数据修改持悲观态度,认为每次数据修改都会发生数据冲突,所以在一个线程对某一个数据进行读写操作后则直接为被读取的数据上锁,直至完成读写操作并更新数据;
乐观锁
与悲观锁相对,乐观锁则认为每次数据都不会发生数据冲突,只会数据更新的时候去判断再次期间数据有无变更;
对比
两个相对各有优缺,但是在大部分场景上来说悲观锁的使用相较较多,因为悲观锁在真正发生数据冲突的时候,可以避免额外锁的开销。如果使用乐观锁虽然减小锁机制的性能开销,但是会经常出现数据冲突,导致上层应用出现问题,反而降低了系统性能。所以在大多情况下悲观锁是相对较优的选择;
实现
悲观锁大多数是依靠数据库本身实现锁机制实现的,例如select * from emp where name=”Smith” for update中,通过 for update 对emp表实现上锁,在事务提交之前,外界是无法对该数据表实现操作的(分别有读锁、写锁、行锁、表锁);
乐观锁大多数基于数据版本记录机制实现的,即在数据读取时会一并读取数据的版本信息,当要更新该条数据的时候会判断更新的数据版本是否和取出的数据版本是否一致,是则予以更新,否则认为是过期数据,拒绝更新,让用户重新操作;
总结
虽然从之前的表述中悲观锁似乎优于乐观锁,但是悲观锁有一个致命的缺陷,就是面对大量高并发访问的时候由于锁机制的存在会造成线程阻塞,甚至是死锁的可能性,为系统带来极大的安全隐患。其次大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观相较宽松的锁机制可以避免了长事务中的数据库加锁开销,大大提升了大并发量下的系统整体性能表现。但是乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,因为来自外部系统的用户更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。所以这些问题都要在系统设计阶段就要考虑各种可能性并进行调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。