乐观锁与悲观锁是一种思想,而不是一种实现。
乐观锁适用于读操作多的场景,它总认为不会产生并发问题,因此每次读数据的时候总认为不会有别的线程对数据进行修改,所以每次都不会上锁,但是在更新的时候会同时记录当前version值,用来判断在此期间有没有其他线程对数据进行修改。
- 关键代码:update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
- 需要手动在数据库中增加字段version,表示被修改的次数,每次修改会加一
- 在提交更新的时候,若记录的version等于数据库中的version则更新成功,若不相等则重试,直到成功。
悲观锁适用于写操作多的场景,与悲观锁相反,它总认为会产生并发问题,因此每次读数据的时候总会认为会有别的线程对数据进行修改,所以每次都会上锁,直到事务提交完毕才会释放锁。数据库中使用了很多这种锁机制,比如读锁、写锁、表锁、写锁,都是在操作之前先上锁,在整个数据处理过程当中,数据都是处于锁定状态,只有当处理完毕,才会释放锁。悲观锁的实现往往是依靠数据库提供的锁机制。在Java中synchronized的实现也是悲观锁思想的一种实现。
关于,共享锁,排它锁,表锁,行锁。用一个问题来解释
MyISAM和InnoDB关于锁方面的区别是什么?
MyISAM默认用的是表级锁,不支持行级锁
InnoDB默认支持的是行级锁,也支持表级锁
关于MyISAM:假设有一条select语句A对数据库操作需要十秒钟,此时如果有另外一条语句B想要更新某一行(即使不在select的范围钟),那么B语句会等待A语句执行完毕之后再执行,这就是MyISAM的表级锁。其原理是,当执行select的时候,会对表加一个读锁,而对数据进行增删改的时候,会对表加一个写锁,当读锁未被释放的时候,另外一个访问想要增加写锁就会被阻塞,直到所有的读锁被释放。可以使用lock tables [table_name] read;手动给表增加读锁,使用unlock tables;可以解锁。
读锁也称为共享锁,可以理解为两条select语句可以同时对一个数据库操作,即使其中一条执行非常慢。写锁也称为排它锁,即不能同时执行,需等待其它写锁释放才能执行。也可再select语句后面加上for update来手动上排它锁,上共享锁是lock in share mode;。
关于InnoDB:由于InnoDB的事务是自动提交的,所以先把自动事务提交关闭:set autocommit=0;然后再对某一行进行select操作,同时另外一个session对这一行数据进行写操作,此操作会被阻塞,但如果此时对其它行数据进行写操作,将会很快的执行成功,这就是行级锁。其他操作与共享锁和排它锁的限制基本一致。
值得一提的是,InnoDB在没有用到索引的时候是用的表级锁。(如果不走索引的select添加读锁,那么此时即使是更新不同行也需要等待读锁解锁。