Java如何实现对Mysql数据库的行锁(java代码实现数据库锁)

如题所述

下面通过一个例子来说明

场景如下:

用户账户有余额,当发生交易时,需要实时更新余额。这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的。

那么如何避免:

网上查了下,有以下两种方法:

1、使用悲观锁

当需要变更余额时,通过代码在事务中对当前需要更新的记录设置forupdate行锁,然后开始正常的查询和更新操作

这样,其他的事务只能等待该事务完成后方可操作

当然要特别注意,如果使用了Spring的事务注解,需要配置一下:

class="org..jdbc.datasource."<

在指定代码处添加事务注解

@

@Override

publicboolean(LonguserId,BigDecimalamount)

throws{

longtime=System.();

//获取对记录的锁定

UserBalancebalance=.getLock(userId);

LOGGER.info("[lock]start.time:{}",time);

if(null==balance){

thrownew(

.ERRORCODE_BALANCE_NOTEXIST,"userbalanceisnotexist");

}

booleanresult=.(balance,amount);

longtimeEnd=System.();

LOGGER.info("[lock]end.time:{}",timeEnd);

returnresult;

}

MyBatis中的锁定方式,实际测试该方法确实可以有效控制,不过在大并发量的情况下,可能会有性能问题吧

select*fromuser_balancewhereid=#{id,jdbcType=BIGINT}forupdate;

]]<

2、使用乐观锁

这个方法也同样可以解决场景中描述的问题(我认为比较适合并不频繁的操作):

设计表的时候增加一个version(版本控制字段),每次需要更新余额的时候,先获取对象,update的时候根据version和id为条件去更新,如果更新回来的数量为0,说明version已经变更

需要重复一次更新操作,如下:sql脚本

updateuser_balancesetBalance=#{balance,jdbcType=DECIMAL},Version=Version1whereId=#{id,jdbcType=BIGINT}andVersion=#{version,jdbcType=BIGINT}

这是一种不使用数据库锁的方法,解决方式也很巧妙。当然,在大量并发的情况下,一次扣款需要重复多次的操作才能成功,还是有不足之处的。不知道还有没有更好的方法。

温馨提示:答案为网友推荐,仅供参考
相似回答