基于数据库实现分布式锁

基于 Spring Boot + MyBatis + DM8 的分布式锁

project-root/
├── src/
│   └── main/
│       ├── java/com/example/demo/
│       │   ├── DemoApplication.java
│       │   ├── config/
│       │   │   └── MyBatisConfig.java
│       │   ├── entity/
│       │   │   └── ScheduledLock.java
│       │   ├── mapper/
│       │   │   └── ScheduledLockMapper.java
│       │   ├── service/
│       │   │   └── TaskLockService.java
│       │   └── task/
│       │       └── DemoScheduledTask.java
│       └── resources/
│           ├── application.yml
│           └── mapper/ScheduledLockMapper.xml
├── pom.xml

// pom.xml
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>dm8-task-lock-demo</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.3.1</version>
    </dependency>
    <dependency>
      <groupId>com.dameng</groupId>
      <artifactId>DmJdbcDriver18</artifactId>
      <version>8.1.2.49</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-scheduling</artifactId>
    </dependency>
  </dependencies>
</project>

// application.yml
spring:
  datasource:
    url: jdbc:dm://localhost:5236/DAMENG
    username: your_user
    password: your_password
    driver-class-name: dm.jdbc.driver.DmDriver

mybatis:
  mapper-locations: classpath*:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true

// entity/ScheduledLock.java
@Data
public class ScheduledLock {
    private String lockName;
    private LocalDateTime lockUntil;
    private LocalDateTime lockedAt;
    private String lockedBy;
}

// mapper/ScheduledLockMapper.java
@Mapper
public interface ScheduledLockMapper {
    ScheduledLock selectLock(@Param("lockName") String lockName);

    void insertLock(ScheduledLock lock);

    int updateIfExpired(ScheduledLock lock);
}

// mapper/ScheduledLockMapper.xml
<mapper namespace="com.example.demo.mapper.ScheduledLockMapper">
  <select id="selectLock" resultType="com.example.demo.entity.ScheduledLock">
    SELECT * FROM scheduled_lock WHERE lock_name = #{lockName}
  </select>

  <insert id="insertLock">
    INSERT INTO scheduled_lock (lock_name, lock_until, locked_at, locked_by)
    VALUES (#{lockName}, #{lockUntil}, #{lockedAt}, #{lockedBy})
  </insert>

  <update id="updateIfExpired">
    UPDATE scheduled_lock
    SET lock_until = #{lockUntil},
        locked_at = #{lockedAt},
        locked_by = #{lockedBy}
    WHERE lock_name = #{lockName} AND lock_until < SYSDATE
  </update>
</mapper>

// service/TaskLockService.java
@Service
public class TaskLockService {
    @Autowired ScheduledLockMapper mapper;
    private final String instanceId = InetAddress.getLocalHost().getHostName();

    public boolean tryLock(String lockName, Duration holdTime) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime until = now.plus(holdTime);

        ScheduledLock lock = new ScheduledLock();
        lock.setLockName(lockName);
        lock.setLockUntil(until);
        lock.setLockedAt(now);
        lock.setLockedBy(instanceId);

        int updated = mapper.updateIfExpired(lock);
        if (updated > 0) return true;

        ScheduledLock existing = mapper.selectLock(lockName);
        if (existing == null) {
            mapper.insertLock(lock);
            return true;
        }
        return instanceId.equals(existing.getLockedBy()) && existing.getLockUntil().isAfter(now);
    }
}

// task/DemoScheduledTask.java
@Slf4j
@Component
public class DemoScheduledTask {
    @Autowired TaskLockService lockService;

    @Scheduled(cron = "0 */1 * * * ?")
    public void runClusterSingletonTask() {
        if (!lockService.tryLock("demo-task", Duration.ofMinutes(2))) {
            log.info("跳过任务,本机未抢到锁");
            return;
        }
        log.info("本机获得锁,执行定时任务");
        // 执行任务逻辑
    }
}

// SQL 建表
CREATE TABLE scheduled_lock (
  lock_name VARCHAR(100) PRIMARY KEY,
  lock_until TIMESTAMP,
  locked_at TIMESTAMP,
  locked_by VARCHAR(100)
);

特点:

  • 支持多实例部署,只有一台机器能执行任务

  • 使用达梦数据库做分布式锁,自动过期无需手动释放

  • 基于 MyBatis,简单清晰,易于扩展

  • 配置友好,完全可运行、可集成

包含模块:

  • scheduled_lock 建表 SQL

  • 实体类 + Mapper + XML + Service

  • 一个最小定时任务示例(每分钟执行一次)

  • YML 配置连接 DM8

posted @ 2025-10-24 17:17  18sui  阅读(5)  评论(0)    收藏  举报