跳到主要内容

# 分布式锁

盘古开发框架基于 Lock4j 提供分布式锁。支持注解声明式和 API 编程式对业务代码在分布式环境下加并发锁。

## 安装相关盘古模块​

- 盘古 Parent
- 基础模块
- 缓存模块

    <parent>
        <groupId>com.gitee.pulanos.pangu</groupId>
        <artifactId>pangu-parent</artifactId>
        <version>latest.version.xxx</version>
        <relativePath/>
    </parent>

    <dependency>
        <groupId>com.gitee.pulanos.pangu</groupId>
        <artifactId>pangu-spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>com.gitee.pulanos.pangu</groupId>
        <artifactId>pangu-cache-spring-boot-starter</artifactId>
    </dependency>

## 本地配置​

> 为便于理解，本文基于本地配置的方式编写。若改为标准的 Nacos 配置中心模式，请参阅：配置中心 章节。

- application.properties
- application-dev.properties

    spring.profiles.active=${spring.profiles.active:dev}

    spring.application.name=pangu-examples-lock-redis-based

    # spring-redis
    spring.redis.host=localhost
    spring.redis.database=1
    spring.redis.port=6379
    spring.redis.password=

    logging.level.root=INFO
    logging.level.com.gitee.pulanos.pangu=INFO

## 基于注解声明​

直接在需要缓存的方法上加上 `@Lock4j` 注解。

### @Lock4j​

分布式锁注解。

名称 | 默认值 | 说明
--- | --- | ---
name | 空字符串 | 用于多个方法锁同一把锁 可以理解为锁资源名称，为空则会使用：包名 + 类名 + 方法名。（一般为空即可）
keys | 空字符串 | 支持 SPEL 表达式，锁的 key = name + keys
acquireTimeout | 3000 | 获取锁超时时间 单位：毫秒。可以理解为排队时常，超过这个时常就退出排队，抛出获取锁超时异常。
expire | 30000 | 过期时间 单位：毫秒。主要是防止死锁，建议估计好你锁方法运行时常，正常没有复杂业务的增删改查最多几秒，留有一定冗余，10 秒足够。默认 30 秒是为了兼容绝大部分场景。

### 代码片段​

    /**
     * 默认获取锁超时 3 秒，30 秒锁过期
     */
    @Lock4j
    public void doBiz() {
        log.info("执行doBiz...");
        ThreadUtil.sleep(25*1000);
    }

    /**
     * 配置获取锁超时时间和锁过期时间 支持 SPEL
     * @param accountId
     */
    @Lock4j(keys = {"#accountId"}, expire = 20000, acquireTimeout = 10000)
    public void doBiz2(Long accountId) {
        log.info("执行doBiz2...");
        ThreadUtil.sleep(20*1000);
    }

## 基于 API 编程​

注入 LockTemplate 对象即可使用。如下代码所示。

    @Component
    public class ApiLockService {

        @Autowired
        private LockTemplate lockTemplate;

        public void apiLock(String userId) {
            //... 各种不需要上锁的操作
            String lockKey = "lock4j:ApiLockService:apiLock:" + userId;
            final LockInfo lockInfo = lockTemplate.lock(lockKey);
            //申请锁失败
            if (null == lockInfo) {
                throw new LockException("业务处理中，请稍后再试...");
            }
            //申请锁成功
            try {
                ThreadUtil.sleep(10000L);
                log.info("执行 apiLock, 当前线程{}", Thread.currentThread().getName());
            } finally {
                lockTemplate.releaseLock(lockInfo);
            }
        }

    }

## 启动入口​

    @SpringBootApplication
    public class LockPanguApplication {
        public static void main(String[] args) {
            PanGuApplicationBuilder.init(LockPanguApplication.class).run(args);
        }
    }

## 本文相关范例源码​

- pangu-examples-lock-redis-based：分布式锁范例

## 下一步​

继续阅读其它章节获取你想要的答案或通过我们的 开发者社区 寻求更多帮助。