3.2、int count = (update t_read_write_lock set w_count=1 where r_count = 0)
3.3、如果count==1,则插入一条上锁日志,锁类型是0,状态是0:insert t_lock_log (resource_id,lock_type,status,create_time) values (#{resource_id},0,0,‘当前时间’);
3.4、提交事务;
}
4、如果3.2的count==1,继续向下执行,否则终止业务
5、执行业务操作,业务操作过程如下
{
5.1、业务库开启事务
5.2、执行业务
5.3、更新锁日志记录的状态为1,条件中必须带上status=0:int updateLogCount = (update t_lock_log set status=1 where id=#{日志记录id} and status = 0)
5.4、if(updateLogCount==1){
5.5、提交事务
}else{
5.6、回滚事务【走到这里说明更新锁日志记录失败了,说明t_lock_log的status被其他地方改掉了,被防止死锁的job修改了】
}
}
6、释放锁,过程如下
{
6.1、开启事务
6.2、释放锁:update t_read_write_lock set w_count=0 where w_count = 1 and resource_id = #{resource_id}
6.3、更新锁日志状态为2:update t_lock_log set status=2 where id = #{日志记录id}
6.4、提交事务
}
2.3、死锁的处理
上面这个是正常流程,如果第 3 步执行完了,也就是上锁 W 锁成功,但是执行到第 6 步之前,系统挂了,此时 W 锁没有释放,会出现死锁。
此时我们需要一个 job,通过这个 job 来释放长时间还未释放的锁,比如过了 10 分钟,锁还未被释放的,job 的逻辑如下
1、获取10分钟之前锁未释放的锁日志列表:select * from t_lock_log where status in (0,1) and create_time+10分钟<=当前时
间的;
2、轮询获取的日志列表,释放锁,操作如下
{
2.1、开启事务
2.2、if(t_lock_log.lock_type==0){
//lock_type为0表示是W锁,下面准备释放W锁
//先将日志状态更新为2,注意条件中带上version作为条件,这里使用到了乐观锁,可以确保并发修改时只有一个count的值为1
int count = (update t_lock_log set status=2 where id = #{日志记录id} and version = #{日志记录.version})
if(count==1){
//将w_count置为0
update t_read_write_lock set w_count=0 where w_count = 1 and resource_id = #{resource_id}
}
}else{
//准备释放R锁
//先将日志状态置为2
int count = (update t_lock_log set status=2 where id = #{日志记录id} and version = #{日志记录.version})
if(count==1){
//将r_count置为r_count-1,注意条件中带上r_count - 1>=0
update t_read_write_lock set r_count=r_count-1 where r_count - 1>=0 and resource_id