91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot基于數據庫實現分布式鎖的案例

發布時間:2021-02-03 13:44:11 來源:億速云 閱讀:296 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關Spring Boot基于數據庫實現分布式鎖的案例的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

1.簡介

分布式鎖的方式有很多種,通常方案有:

網上的實現方式有很多,本文主要介紹的是如果使用mysql實現簡單的分布式鎖,加鎖流程如下圖:

Spring Boot基于數據庫實現分布式鎖的案例

其實大致思想如下:

1.根據一個值來獲取鎖(也就是我這里的tag),如果當前不存在鎖,那么在數據庫插入一條記錄,然后進行處理業務,當結束,釋放鎖(刪除鎖)。

2.如果存在鎖,判斷鎖是否過期,如果過期則更新鎖的有效期,然后繼續處理業務,當結束時,釋放鎖。如果沒有過期,那么獲取鎖失敗,退出。

2.數據庫設計

2.1 數據表介紹

數據庫表是由JPA自動生成的,稍后會對實體進行介紹,內容如下:

CREATE TABLE `lock_info` (
 `id` bigint(20) NOT NULL,
 `expiration_time` datetime NOT NULL,
 `status` int(11) NOT NULL,
 `tag` varchar(255) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `uk_tag` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

其中:

  • id:主鍵

  • tag:鎖的標示,以訂單為例,可以鎖訂單id

  • expiration_time:過期時間

  • status:鎖狀態,0,未鎖,1,已經上鎖

3.實現

本文使用SpringBoot 2.0.3.RELEASE,MySQL 8.0.16,ORM層使用的JPA。

3.1 pom

新建項目,在項目中加入jpa和mysql依賴,完整內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.3.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.dalaoyang</groupId>
 <artifactId>springboot2_distributed_lock_mysql</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>springboot2_distributed_lock_mysql</name>
 <description>springboot2_distributed_lock_mysql</description>

 <properties>
  <java.version>1.8</java.version>
 </properties>

 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.16.22</version>
   <scope>provided</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>

3.2 配置文件

配置文件配置了一下數據庫信息和jpa的基本配置,如下:

server.port=20001


##數據庫配置
##數據庫地址
spring.datasource.url=jdbc:mysql://localhost:3306/lock?characterEncoding=utf8&useSSL=false
##數據庫用戶名
spring.datasource.username=root
##數據庫密碼
spring.datasource.password=12345678
##數據庫驅動
spring.datasource.driver-class-name=com.mysql.jdbc.Driver


##validate 加載hibernate時,驗證創建數據庫表結構
##create 每次加載hibernate,重新創建數據庫表結構,這就是導致數據庫表數據丟失的原因。
##create-drop  加載hibernate時創建,退出是刪除表結構
##update     加載hibernate自動更新數據庫結構
##validate 啟動時驗證表的結構,不會創建表
##none 啟動時不做任何操作
spring.jpa.hibernate.ddl-auto=update

##控制臺打印sql
spring.jpa.show-sql=true
##設置innodb
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

3.3 實體類

實體類如下,這里給tag字段設置了唯一索引,防止重復插入相同的數據:

package com.dalaoyang.entity;


import lombok.Data;
import javax.persistence.*;
import java.util.Date;

@Data
@Entity
@Table(name = "LockInfo",
  uniqueConstraints={@UniqueConstraint(columnNames={"tag"},name = "uk_tag")})
public class Lock {

 public final static Integer LOCKED_STATUS = 1;
 public final static Integer UNLOCKED_STATUS = 0;

 /**
  * 主鍵id
  */
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 /**
  * 鎖的標示,以訂單為例,可以鎖訂單id
  */
 @Column(nullable = false)
 private String tag;

 /**
  * 過期時間
  */
 @Column(nullable = false)
 private Date expirationTime;

 /**
  * 鎖狀態,0,未鎖,1,已經上鎖
  */
 @Column(nullable = false)
 private Integer status;

 public Lock(String tag, Date expirationTime, Integer status) {
  this.tag = tag;
  this.expirationTime = expirationTime;
  this.status = status;
 }

 public Lock() {
 }
}

3.4 repository

repository層只添加了兩個簡單的方法,根據tag查找鎖和根據tag刪除鎖的操作,內容如下:

package com.dalaoyang.repository;

import com.dalaoyang.entity.Lock;
import org.springframework.data.jpa.repository.JpaRepository;


public interface LockRepository extends JpaRepository<Lock, Long> {

 Lock findByTag(String tag);

 void deleteByTag(String tag);
}

3.5 service

service接口定義了兩個方法,獲取鎖和釋放鎖,內容如下:

package com.dalaoyang.service;


public interface LockService {

 /**
  * 嘗試獲取鎖
  * @param tag 鎖的鍵
  * @param expiredSeconds 鎖的過期時間(單位:秒),默認10s
  * @return
  */
 boolean tryLock(String tag, Integer expiredSeconds);

 /**
  * 釋放鎖
  * @param tag 鎖的鍵
  */
 void unlock(String tag);
}

實現類對上面方法進行了實現,其內容與上述流程圖中一致,這里不在做介紹,完整內容如下:

package com.dalaoyang.service.impl;

import com.dalaoyang.entity.Lock;
import com.dalaoyang.repository.LockRepository;
import com.dalaoyang.service.LockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.Objects;


@Service
public class LockServiceImpl implements LockService {

 private final Integer DEFAULT_EXPIRED_SECONDS = 10;

 @Autowired
 private LockRepository lockRepository;

 @Override
 @Transactional(rollbackFor = Throwable.class)
 public boolean tryLock(String tag, Integer expiredSeconds) {
  if (StringUtils.isEmpty(tag)) {
   throw new NullPointerException();
  }
  Lock lock = lockRepository.findByTag(tag);
  if (Objects.isNull(lock)) {
   lockRepository.save(new Lock(tag, this.addSeconds(new Date(), expiredSeconds), Lock.LOCKED_STATUS));
   return true;
  } else {
   Date expiredTime = lock.getExpirationTime();
   Date now = new Date();
   if (expiredTime.before(now)) {
    lock.setExpirationTime(this.addSeconds(now, expiredSeconds));
    lockRepository.save(lock);
    return true;
   }
  }
  return false;
 }

 @Override
 @Transactional(rollbackFor = Throwable.class)
 public void unlock(String tag) {
  if (StringUtils.isEmpty(tag)) {
   throw new NullPointerException();
  }
  lockRepository.deleteByTag(tag);
 }

 private Date addSeconds(Date date, Integer seconds) {
  if (Objects.isNull(seconds)){
   seconds = DEFAULT_EXPIRED_SECONDS;
  }
  Calendar calendar = Calendar.getInstance();
  calendar.setTime(date);
  calendar.add(Calendar.SECOND, seconds);
  return calendar.getTime();
 }
}

3.6 測試類

創建了一個測試的controller進行測試,里面寫了一個test方法,方法在獲取鎖的時候會sleep 2秒,便于我們進行測試。完整內容如下:

package com.dalaoyang.controller;

import com.dalaoyang.service.LockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

 @Autowired
 private LockService lockService;

 @GetMapping("/tryLock")
 public Boolean tryLock(String tag, Integer expiredSeconds) {
  return lockService.tryLock(tag, expiredSeconds);
 }

 @GetMapping("/unlock")
 public Boolean unlock(String tag) {
  lockService.unlock(tag);
  return true;
 }

 @GetMapping("/test")
 public String test(String tag, Integer expiredSeconds) {
  if (lockService.tryLock(tag, expiredSeconds)) {
   try {
    //do something
    //這里使用睡眠兩秒,方便觀察獲取不到鎖的情況
    Thread.sleep(2000);
   } catch (Exception e) {

   } finally {
    lockService.unlock(tag);
   }
   return "獲取鎖成功,tag是:" + tag;
  }
  return "當前tag:" + tag + "已經存在鎖,請稍后重試!";
 }
}

3.測試

項目使用maven打包,分別使用兩個端口啟動,分別是20000和20001。

java -jar springboot2_distributed_lock_mysql-0.0.1-SNAPSHOT.jar --server.port=20001
java -jar springboot2_distributed_lock_mysql-0.0.1-SNAPSHOT.jar --server.port=20000

分別訪問兩個端口的項目,如圖所示,只有一個請求可以獲取鎖。

Spring Boot基于數據庫實現分布式鎖的案例

Spring Boot基于數據庫實現分布式鎖的案例

感謝各位的閱讀!關于“Spring Boot基于數據庫實現分布式鎖的案例”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

咸阳市| 西华县| 楚雄市| 南靖县| 济源市| 安达市| 中宁县| 昭平县| 城市| 石屏县| 如东县| 洱源县| 南通市| 万源市| 双辽市| 綦江县| 高阳县| 宜兴市| 汉寿县| 汉阴县| 昌吉市| 邯郸县| 麻城市| 息烽县| 四川省| 罗平县| 游戏| 镇坪县| 林芝县| 瑞丽市| 阳东县| 巩义市| 分宜县| 财经| 昭通市| 阳山县| 扎鲁特旗| 和顺县| 奉节县| 荃湾区| 江西省|