跳至主要內容

锁的问题

知识库实战项目高可用高并发架构高可用高并发架构大约 2 分钟

锁和事务的区别

  • 锁:为了在高并发(多线程)模式下,防止共享资源出现并发修改的情况,锁为多线程而生。
  • 事务:一次会话,一个线程的原子操作,保证一些操作要么都成功,要么都失败。
  • 分布式锁:在多个进程模式下,防止多个进程共享数据的并发修改,分布式锁是解决多个客户端对共享资源的互斥访问。
  • 分布式事务:多个事务存在与多个 jvm 进程中,保证多个进程要么多成功,要么多失败。

分布式锁

分布式锁: MySQL,Redis, zookeeper 以上三个服务都可以作为第三方加锁的服务;

// MySQL悲观锁的实现方式 加上for update ,表示所有的线程执行此方法的时候,都是互斥的访问关系;
@select(value="select * from table where id = #{seckillId} for update")
EntityVo selectByPrimaryKeyBySQLLock(Long seckillId )

// MySQ乐观锁的实现方式
@Update(value = "UPDATE table SET stock_count= stock_count-1,version=version+1 WHERE id = #{seckillId} AND version = #{version}")
int updateSeckillGoodsByPrimaryKeyByVersion(@Param("seckillId") Long seckillId, @Param("version") Integer version);

Redis 锁

Redis 分布式锁: 基于内存的高性能的锁,但是存在问题。
Redis 是 AP 模型的数据库,因此在海量的数据模式下,存在数据丢失的可能,Redis 丢失的概率 < mysql
Redis 使用 RedLock 解决锁丢失的问题;
Redisson 分布式锁实现框架: 可重入锁,锁续航,RedLock 都已经实现了;

@Component
@Scope
@Aspect
@Order(1)
public class LockRedisAspect {
    // 注入request
    @Autowired
    private HttpServletRequest request;

    // service 切入点
    @Pointcut("@annotation(com.sugo.seckill.aop.redis.ServiceRedisLock)")
    public void lockAspect(){}

    @Around("lockAspect()")
    public Object around(ProceedingJoinPoint joinPoint){
        // 获取请求参数
        String str = request.getRequestURI();
        String killId = str.substring(str.lastIndexOf("/")-1,str.lastIndexOf("/"));
        Object obj = null;
        // 使用redis锁
        boolean res = RedissLockUtil.tryLock("seckill_goods_lock_" + killId,TimeUnit.SECONDS,3,10);
        try {
            //加锁成功,执行业务
            if(res){
                obj = joinPoint.proceed();
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }finally {
            // 释放锁
          if(res){
              RedissLockUtil.unlock("seckill_goods_lock_" + killId);
          }
        }
        return obj;
    }
}