通常锁分为悲观锁和乐观锁,所谓悲观锁就是处处提防着其人操作,生怕别人和自己抢资源,所以一上来就加锁了;而乐观锁就是老是乐天派觉得没人会和自己抢资源,只要按照规则来就没事,是自己通过数据库设定一个数据库字段来模拟锁机制,是一个君子协议,乐观的认为大家都是君子都会遵守。悲观锁分读锁和写锁,无论是读锁还是写锁,都不影响查询,查询大家都可以执行而且获取到结果,两把锁的区别就是读锁可以共享锁可以同时多人持有锁,大家都拿着号等着随时更新数据的权利,谁手快谁先更新,但是写锁就只能一次只有一人拿着号,只有等当前用户操作完全完成了,其他人才可以拿到号进行更新操作,就像排队进行一样,锁还分行级锁和整个表的锁,行级锁只是锁当前id指定的行,而整表锁就是直接锁在表上,没有where条件限制,在mysql中具体语法如下:
读锁(也叫共享锁)就是查询的时候不希望数据被其他人修改,这时可以设置读的共享模式锁,大家都可以读取,读取数据不受限制,都可以持有读取共享锁,但是如果其中一个人没有提交事务,另一个人就不能修改当前锁定的表,当然如果没有其他人同时持有读取锁,只有自己持有,那么自己是可以修改数据的,不过只要有两人同时持有读取锁,那么一方就不能随意修改数据,读取共享锁语法是在事务中 select * from 表名 lock in share model
写锁(也叫排他锁),写锁不能共享,只要有人加了写锁,那么其他人就不能做加锁操作,哪怕是加共享锁,反正当前行或表数据的锁只能一个人持有这把锁,其他人不能同时持有,其他人想修改持有写锁,只能等上一个人提交事务后才能获取到写锁,不然就得一直等待,此时就算不是去获取锁,热只是想修改数据也得等待上一个人事务提交,但是如果只是查询操作还是不受限制的
如果一直等不到其他人事务提交,那么就有可能更新操作超时,会报错,但是数据没问题,只是更新失败,这时代码加异常捕获处理即可,在mysql中sql加悲观锁是通过lack关键字,但是在Hibernate又该如何添加悲观锁呢?就是调用Hibernate方法时通过指定参数lockOptions这个枚举来让Hibernate决定生成sql时如何添加lock关键字,如下:
hibernate生成的是行级锁,有where条件限制,只在当前行上加锁,其他行并没有加锁,其他人可以对其他没有加锁的行数据进行修改或加锁,这样细粒度划分可以提高mysql的执行效率,不需要一锁就锁整张表,搞的大家都得等,就像一人上厕所,本来只要占一个坑就行,却偏偏对整个厕所来个包场,显然就不合理了。
=====================================================
乐观锁:其实乐观锁不是数据库本身提供的锁机制,是人为模拟实现的,如添加一个字段如version,其取值为默认递增的整数,默认值为1,只要有一个人进来就把值在先前基础上加1,不用等待,但是大家都得遵守一个约定就是提交之前先去数据库判断一下version版本是否和自己当前版本一致,如果不一致那么先把数据更新了,保证和数据库数据一致再进行提交,类似于svn控制版本冲突的解决思路,这个解决思路在hibernate中也是支持的,不需要自己在手动添加version版本号,只需要在hibernate中配置一下,hibernate会自己实现乐观锁机制,如下:
步骤1、在实体类中添加一个integer类型的version字段,并实现get,set方法
步骤2、在实体类对应的xml配置文件中,添加version属性,注意version出现的位置在id属性之后,在property属性之前
注意如果hibernate配置的不是update更新数据库,那么需要自己到数据库添加一个名为version的int类型字段,不然hibernate无法进行版本维护,这样每次进行数据更新操作后,数据所在行的版本就会相应加1,当hibernate在进行update操作之前发现version版本不对,那么就不会成功执行update语句,会报错给出提示,当前行数据已被另一个事务修改