分佈式鎖總結

分佈式鎖方案html

MySQL

Version 樂觀鎖

Redis

SETNX PX命令,LUA腳本(推薦)

Spring Integration Redis

引入依賴
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.boot:spring-boot-starter-integration'
    implementation 'org.springframework.integration:spring-integration-redis'
}
添加配置(Spring Boot自動裝配)
spring:
  redis:
    host: localhost
    port: 6379
@Bean
    public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
        RedisLockRegistry redisLockRegistry = new RedisLockRegistry(redisConnectionFactory, "redisLockRegistry");
        return redisLockRegistry;
    }
編碼演示
private RedisLockRegistry redisLockRegistry;

    public void process(String orderNo) {
        Lock lock = redisLockRegistry.obtain("orderNo:" + orderNo);
        boolean result = false;
        try {
            result = lock.tryLock(1000L, TimeUnit.MICROSECONDS);
            if (result) {
                //todo
            }
        } catch (InterruptedException e) {
            //
            log.error("lock error", e);
        } finally {
            if (result) {
                lock.unlock();
            }
        }
    }

    public RedisLockRegistry getRedisLockRegistry() {
        return redisLockRegistry;
    }

    @Autowired
    public void setRedisLockRegistry(RedisLockRegistry redisLockRegistry) {
        this.redisLockRegistry = redisLockRegistry;
    }

Redission

<dependency>
     <groupId>org.redisson</groupId>
     <artifactId>redisson-spring-boot-starter</artifactId>
     <version>3.12.5</version>
 </dependency>

Zookeeper

臨時有序節點 +【Watcher機制】

Apache Curator 自行查閱

Spring Integration ZooKeeper

引入依賴
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-integration'
    implementation 'org.springframework.integration:spring-integration-zookeeper'
    implementation 'org.apache.curator:curator-recipes:4.3.0'
}
添加配置
spring:
  zookeeper:
    server: localhost:2181
@Value("${spring.zookeeper.server}")
    private String connectString;

    @Bean
    public CuratorFramework curatorFramework() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectString,retryPolicy);
        curatorFramework.start();
        return curatorFramework;
    }


    @Bean
    public ZookeeperLockRegistry zookeeperLockRegistry(CuratorFramework curatorFramework) {
        ZookeeperLockRegistry zookeeperLockRegistry = new ZookeeperLockRegistry(curatorFramework);
        return zookeeperLockRegistry;
    }
編碼演示
private ZookeeperLockRegistry zookeeperLockRegistry;

    public void process(String orderNo) {
        Lock lock = zookeeperLockRegistry.obtain("orderNo:" + orderNo);
        boolean result = false;
        try {
            result = lock.tryLock(1000L, TimeUnit.MICROSECONDS);
            if (result) {
                //todo
            }
        } catch (InterruptedException e) {
            //
            log.error("lock error", e);
        } finally {
            if (result) {
                lock.unlock();
            }
        }
    }

    public ZookeeperLockRegistry getZookeeperLockRegistry() {
        return zookeeperLockRegistry;
    }

    @Autowired
    public void setZookeeperLockRegistry(ZookeeperLockRegistry zookeeperLockRegistry) {
        this.zookeeperLockRegistry = zookeeperLockRegistry;
    }

使用Spring AOP和SpEL 自定義註解

註解類

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DistributedLock {

    String expression() default "";

    long expire() default 60000L;

    TimeUnit timeUnit() default TimeUnit.SECONDS;
}

AOP切面

private RedisLockRegistry redisLockRegistry;

    @Pointcut("@annotation(DistributedLock)")
    public void distributedLockAspect() {
    }

    @Around(value = "distributedLockAspect()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Class targetClass = pjp.getTarget().getClass();
        String methodName = pjp.getSignature().getName();
        Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getMethod().getParameterTypes();
        Method method = targetClass.getMethod(methodName, parameterTypes);
        Object[] arguments = pjp.getArgs();
        DistributedLock annotation = method.getAnnotation(DistributedLock.class);
        String lockKey = arguments.length > 0 && !StringUtils.isEmpty(annotation.expression()) ? getLockKey(annotation, arguments) : targetClass.getName() + ":" + methodName;
        Lock lock = redisLockRegistry.obtain(lockKey);
        boolean result = false;
        try {
            result = lock.tryLock(annotation.expire(), annotation.timeUnit());
            if (result) {
                return pjp.proceed();
            }
        } catch (InterruptedException e) {
            //
            log.error("lock error", e);
        } finally {
            if (result) {
                lock.unlock();
            }
        }
        throw new LockException("lock error");
    }

    private String getLockKey(DistributedLock annotation, Object[] arguments) {
        ExpressionParser parser = new SpelExpressionParser();
        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
        context.setVariable("arg", arguments);
        return parser.parseExpression(annotation.expression()).getValue(context, String.class);
    }

使用栗子

/**
     * 使用第一個參數
     *
     * @param orderNo
     */
    @DistributedLock(expression = "#arg[0]")
    public void process1(String orderNo) {
        //todo
        log.info("working....");
    }

    /**
     * 使用第二個參數的name屬性
     *
     * @param orderNo
     * @param user
     */
    @DistributedLock(expression = "#arg[1].name")
    public void process1(String orderNo, User user) {
        //todo
        log.info("working....");
    }

    /**
     * 使用第一個參數和第二個參數的name屬性
     *
     * @param orderNo
     * @param user
     */
    @DistributedLock(expression = "#arg[0] + #arg[1].name")
    public void process2(String orderNo, User user) {
        //todo
        log.info("working....");
    }

    /**
     * 使用常量
     *
     * @param orderNo
     * @param user
     */
    @DistributedLock(expression = "'test3'")
    public void process3(String orderNo, User user) {
        //todo
        log.info("working....");
    }
相關文章
相關標籤/搜索