MYSQL悲观锁-用户余额

无论什么锁JAVA的synchronized也好,还是MYSQL的锁都好,要注意分布式环境与单机环境

1.乐观锁

乐观认为并发不高,甚至没有并发。其中一种实现方式依靠在表中多加一个版本号字段,每次查询更新就按这个版本号,假设在修改时版本号与数据库不一致,就需要尝试重连(重新执行)。

查询
SELECT * FROM user WHERE id = #{id}
修改
UPDATE user SET .... WHERE id = #{id} AND version = #{version}

缺点:当出现并发时,可能会一直尝试重连

2.悲观锁

悲观认为并发经常出现,比如用户的余额问题。需要注意在Spring-Boot中悲观锁需要再事务逻辑中才会生效。悲观锁分为两种

悲观锁锁类 = 查询字段为索引 ? 行级锁 : 表级锁
实现方式

Mapper(核心为末尾的FOR UPDATE关键词)

@Select("SELECT * FROM person WHERE id = #{0} FOR UPDATE")
Person selectMoneyById(Integer id);

Service(核心为开头的事务)

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deductTicket(Integer aud, Integer ticket) 
        log.info("线程{}:start", Thread.currentThread().getName());
        Person person = baseMapper.selectMoneyById(aud);
        
		// 上面会阻塞,直到解锁(事务结束)
        log.info("线程{}:mid => {}", Thread.currentThread().getName(), person)
        
		if (person.getTicket() < ticket) {
            log.info("余额不足 => aud:{},targetTicket:{},nowTicket:{}", aud, ticket, person.getTicket());
            log.info("线程{}:end", Thread.currentThread().getName());
            return false;
        }
        
		// 加个延时看效果
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        baseMapper.updateById(person.setTicket(person.getTicket() - ticket));
        log.info("扣款成功 => aud:{},targetTicket:{},nowTicket:{}", aud, ticket, person.getTicket());
        log.info("线程{}:end", Thread.currentThread().getName());
        return true;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值