悲观锁
悲观锁其实就是mysql数据库自带的行锁。只要在查询语句后附加 for update,数据库就会将查询的数据加上行锁,会开启一个事务,无法被其他线程使用。只能当前线程提交事务后,会释放锁。
//查询条件附带 for update就是加悲观锁
EntryObj entry = query("select * from table where id = #{newEntry.id} for update");
乐观锁
乐观锁是自己实现的,算不上是一个锁,但是起了锁的作用。
具体原理如下:
将数据库表里加入version字段进行版本控制,update操作时 更新条件version=#{version}+1 where是带上 version=#{version},如果版本与查询的对不上,则更新失败,可以重复查询操作再次更新。
public boolean updateEntry(EntryObject newEntry){
boolean result = false;
//失败后尝试次数,防止死循环
int retryNum = 5;
while (retryNum > 0){
//查询指定记录
EntryObject entry = query("select * from table where id = #{newEntry.id}");
//修改记录 但不修改版本号
newEntry.setVersion(entry.getVersion());
//update操作,where根据版本号,并且跟新版本号+1
int count = update("update table set name=#{name},version=#{version}+1 where id = #{newEntry.id} and version = #{newEntry.version}");
//更新成功,返回true,推出循环
if(count == 1){
result = true;
break;
}
//不成功重新尝试,尝试次数减少一次
retryNum--;
}
return result;
}
乐观锁和悲观锁各有各自的好处。乐观锁性能好并不会影响读取数据,且直到提交才锁定,并不会产生死锁,但可能会出现脏读现象。悲观锁则是完全锁住数据,虽然可能影响性能,但好处就是更稳定。各有各的适用场景。