锁的问题
大约 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;
}
}