所谓悲观锁:也就是说数据库悲剧了。它是由底层数据库控制的。
举例;当你操作一个表的时候。他就会给加上一个锁。只有你自己能操作这张表,在数据提交之前别人是无法操作这个表的。这就是悲观锁。所以它的效率也是非常低的。安全性较高。
如何用呢:
即:student student=(Studnet)session.get(Student.class,1,LockMode.UPGRADE).
执行这行代码时它就会给你上锁:select * from Student where id=1 for update;
只有你提交之后才别人才能操作这张表。
所谓乐观锁:是由应用程序提供的一种机制,这种机制既能保证多个事物并发访问数据又能防止第二类丢失更新问题。一般开发中用乐观锁比较多。用悲观锁较少。
原理:在你操作一张student表的时候,例如查询一个id为1的学生。他不仅仅是根据id来查询的。他还会根据当前表的版本号或时间戳来进行是否继续操作。
例如你在操作一张表更新分数,你首先查询到一个学生,查出来了她的分数,而另一个人也同时在获取到了这个学生的分数也要对其更新。当你进行更新的时候,首先hibernate会帮你查看数据表的version是多少,如果你们的version相等,就会更新当前的version自增1,同时也更新了分数,那么就更新成功。当你提交后,另一个人再对其更新,他也是根据id和当前的version来更新分数,但是他发现这时候,version并不相等。因为你已经更新了啊。所以他就会抛出一个异常:StaleObjectStaleException的异常。
好看一张图你就明白了。
那么如何实现乐观锁呢。有两种方式:
可以利用hibernate提供的版本功能来实现乐观锁,对象-关系映射文件中的<version>元素和<timestamp>元素都具有版本控制功能
1.<version>元素:通过利用一个递增的整数来跟踪数据库表中记录的版本,
2.<timestamp>元素利用时间戳来跟踪数据库表中记录的版本
第一种方式:
首先在类里面添加一个字段:private int version 并提供getter,setter方法
然后在映射文件中添加一个元素:<version name="version" column="version" type="int"></version>
当然你的表里面必须要有这个version字段啊。
第二种方式:
和第一种方式本质上是一样的。
首先在类里面添加一个字段:private Date version 并提供getter,setter方法
然后在映射文件中添加一个元素:<timestamp name="version" column="version" type="date"></timestamp>
表里面也必须要有这个version字段啊。
还有第三种方式。比较少用。就是当你的数据库不能变更的时候。不能添加字段的时候可以在映射文件中的class中添加一个属性:optimistic-lock="all"
这种方式和上面两张方式不一样了。例如更新的时候。他会最大限度的精确当前这个对象。加载当前对象的所有属性值。
updte student set grade=100 where id=1 and name="zhangsan" and age=18
over.....