国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

這篇具有很好參考價值的文章主要介紹了?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

看完該文預(yù)計(jì)用時:15分鐘

看之前應(yīng)具體的技術(shù)棧:springboot mysql nginx(了解即可)

目錄

0.寫在前面

1. 從減庫存聊起

1.1. 環(huán)境準(zhǔn)備

??1.2. 簡單實(shí)現(xiàn)減庫存

?1.3. 演示超賣現(xiàn)象

1.4. jvm鎖問題演示?

1.4.2. 原理

1.5. 多服務(wù)問題?

1.5.1. 安裝配置nginx

1.5.2. 壓力測試

?1.6. mysql鎖演示

1.6.1. mysql悲觀鎖

1.6.2. mysql樂觀鎖?

?1.6.3. mysql鎖缺陷

?2. 基于mysql實(shí)現(xiàn)分布式鎖

2.1. 基本思路?

2.2. 代碼實(shí)現(xiàn)

2.3. 缺陷及解決方案?


0.寫在前面

在多線程高并發(fā)場景下,為了保證資源的線程安全問題,jdk為我們提供了synchronized關(guān)鍵字和
ReentrantLock可重入鎖,但是它們只能保證一個jvm內(nèi)的線程安全。在分布式集群、微服務(wù)、云原生橫行的當(dāng)下,如何保證不同進(jìn)程、不同服務(wù)、不同機(jī)器的線程安全問題,jdk并沒有給我們提供既有的解決方案。此時,我們就必須借助于相關(guān)技術(shù)手動實(shí)現(xiàn)了。目前主流的實(shí)現(xiàn)有三種方式:
1. 基于mysql關(guān)系型實(shí)現(xiàn)
2. 基于redis非關(guān)系型數(shù)據(jù)實(shí)現(xiàn)
3. 基于zookeeper實(shí)現(xiàn)

這篇文章主要講解的是基于基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

1. 從減庫存聊起

庫存在并發(fā)量較大情況下很容易發(fā)生超賣現(xiàn)象,一旦發(fā)生超賣現(xiàn)象,就會出現(xiàn)多成交了訂單而發(fā)不了貨的情況。

場景:
????????商品S庫存余量為5時,用戶A和B同時來購買一個商品S,此時查詢庫存數(shù)都為5,庫存充足則開始減庫存:
用戶A:update db_stock set stock = stock - 1 where id = 1
用戶B:update db_stock set stock = stock - 1 where id = 1
并發(fā)情況下,更新后的結(jié)果可能是4,而實(shí)際的最終庫存量應(yīng)該是3才對

1.1. 環(huán)境準(zhǔn)備

為了模擬具體場景我們需要準(zhǔn)備開發(fā)環(huán)境

首先需要在mysql數(shù)據(jù)庫中準(zhǔn)備一張表:

CREATE TABLE `db_stock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_code` varchar(255) DEFAULT NULL COMMENT '商品編號',
`stock_code` varchar(255) DEFAULT NULL COMMENT '倉庫編號',
`count` int(11) DEFAULT NULL COMMENT '庫存量',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

?表中數(shù)據(jù)如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?創(chuàng)建分布式鎖demo工程:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?建立以下工具目錄結(jié)構(gòu):

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?pom依賴文件:


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

?application.yml配置文件:

server:
  port: 6000
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://172.16.116.100:3306/test
    username: root
    password: root

DistributedLockApplication啟動類:

@SpringBootApplication
@MapperScan("com.atguigu.distributedlock.mapper")

public class DistributedLockApplication {
 ? ?public static void main(String[] args) {
 ? ? ? ?SpringApplication.run(DistributedLockApplication.class, args);
 ? }
}

Stock實(shí)體類:

@Data
@TableName("db_stock")
public class Stock {
 ? @TableId
 ? private Long id;
 ? private String productCode;
 ? private String stockCode;
 ? private Integer count;
}

StockMapper接口:

public interface StockMapper extends BaseMapper<Stock> {
}

??1.2. 簡單實(shí)現(xiàn)減庫存

接下來咱們代碼實(shí)操一下

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

StockController:

@RestController
public class StockController {
    @Autowired
    private StockService stockService;
    @GetMapping("check/lock")
    public String checkAndLock(){
        this.stockService.checkAndLock();
        return "驗(yàn)庫存并鎖庫存成功!";
    }
}

StockService:

@Service
public class StockService {
    @Autowired
    private StockMapper stockMapper;

    public void checkAndLock() {
// 先查詢庫存是否充足
        Stock stock = this.stockMapper.selectById(1L);
// 再減庫存
        if (stock != null && stock.getCount() > 0) {
            stock.setCount(stock.getCount() - 1);
            this.stockMapper.updateById(stock);
        }
    }
}

測試:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?

?查看數(shù)據(jù)庫:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

在瀏覽器中一個一個訪問時,每訪問一次,庫存量減1,沒有任何問題。

?1.3. 演示超賣現(xiàn)象

接下來咱們使用jmeter壓力測試工具,高并發(fā)下壓測一下,添加線程組:并發(fā)100循環(huán)50次,即5000次請求。

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

??【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?給線程組添加HTTP Request請求:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

填寫測試接口路徑如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

再選擇你想要的測試報(bào)表,例如這里選擇聚合報(bào)告:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

啟動測試,查看壓力測試報(bào)告:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

測試結(jié)果:請求總數(shù)5000次,平均請求時間202ms,中位數(shù)(50%)請求是在173ms內(nèi)完成的,90%請求是在344ms內(nèi)完成的,最小耗時12ms,最大耗時1125ms,錯誤率0%,每秒鐘平均473.8次。

查看mysql數(shù)據(jù)庫剩余庫存數(shù):還有4870

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

此時如果還有人來下單,就會出現(xiàn)超賣現(xiàn)象(別人購買成功,而無貨可發(fā))。

1.4. jvm鎖問題演示?

使用jvm鎖(synchronized關(guān)鍵字或者ReetrantLock)試試:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?重啟tomcat服務(wù),再次使用jmeter壓力測試,效果如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

查看mysql數(shù)據(jù)庫:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?并沒有發(fā)生超賣現(xiàn)象,完美解決。 ?

1.4.2. 原理

添加synchronized關(guān)鍵字之后,StockService就具備了對象鎖,由于添加了獨(dú)占的排他鎖,同一時刻只 有一個請求能夠獲取到鎖,并減庫存。此時,所有請求只會one-by-one執(zhí)行下去,也就不會發(fā)生超賣現(xiàn)象。?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

1.5. 多服務(wù)問題?

?使用jvm鎖在單工程單服務(wù)情況下確實(shí)沒有問題,但是在集群情況下會怎樣? 接下啟動多個服務(wù)并使用nginx負(fù)載均衡,結(jié)構(gòu)如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

啟動三個服務(wù)(端口號分別8000 8100 8200),如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

1.5.1. 安裝配置nginx

基于安裝nginx:

# 拉取鏡像

docker pull nginx:latest

# 創(chuàng)建nginx對應(yīng)資源、日志及配置目錄

mkdir -p /opt/nginx/logs /opt/nginx/conf /opt/nginx/html

# 先在conf目錄下創(chuàng)建nginx.conf文件,配置內(nèi)容參照下方

# 再運(yùn)行容器

docker run -d -p 80:80 --name nginx -v /opt/nginx/html:/usr/share/nginx/html 

-v /opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v 
/opt/nginx/logs:/var/log/nginx nginx
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    #include /etc/nginx/conf.d/*.conf;
	
	upstream distributed {
		server 172.16.116.1:8000;
		server 172.16.116.1:8100;
		server 172.16.116.1:8200;
	}
	
	server {
		listen       80;
        server_name  172.16.116.100;
		location / {
			proxy_pass http://distributed;
		}
	}
	
}

?在瀏覽器中測試:172.16.116.100是我的nginx服務(wù)器地址

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?經(jīng)過測試,通過nginx訪問服務(wù)一切正常。

1.5.2. 壓力測試

?注意:先把數(shù)據(jù)庫庫存量還原到5000。

參照之前的測試用例,再創(chuàng)建一個新的測試組:參數(shù)給之前一樣

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

配置nginx的地址及 服務(wù)的訪問路徑如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?測試結(jié)果:性能只是略有提升。

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?數(shù)據(jù)庫庫存剩余量如下:

?又出現(xiàn)了并發(fā)問題,即出現(xiàn)了超賣現(xiàn)象。

?1.6. mysql鎖演示

除了使用jvm鎖之外,還可以使用數(shù)據(jù)鎖:悲觀鎖 或者 樂觀鎖

悲觀鎖:在讀取數(shù)據(jù)時鎖住那幾行,其他對這幾行的更新需要等到悲觀鎖結(jié)束時才能繼續(xù) 。 樂觀所:讀取數(shù)據(jù)時不鎖,更新時檢查是否數(shù)據(jù)已經(jīng)被更新過,如果是則取消當(dāng)前更新,一般在悲觀鎖 的等待時間過長而不能接受時我們才會選擇樂觀鎖。

1.6.1. mysql悲觀鎖

在MySQL的InnoDB中,預(yù)設(shè)的Tansaction isolation level 為REPEATABLE READ(可重讀)

在SELECT 的讀取鎖定主要分為兩種方式:

  • SELECT ... LOCK IN SHARE MODE (共享鎖)
  • SELECT ... FOR UPDATE (悲觀鎖)

這兩種方式在事務(wù)(Transaction) 進(jìn)行當(dāng)中SELECT 到同一個數(shù)據(jù)表時,都必須等待其它事務(wù)數(shù)據(jù)被提交(Commit)后才會執(zhí)行。 而主要的不同在于LOCK IN SHARE MODE 在有一方事務(wù)要Update 同一個表單時很容易造成死鎖。簡單的說,如果SELECT 后面若要UPDATE 同一個表單,最好使用SELECT ... FOR UPDATE。

代碼實(shí)現(xiàn)改造StockService:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

在StockeMapper中定義selectStockForUpdate方法:

public interface StockMapper extends BaseMapper<Stock> {
 ? ?public Stock selectStockForUpdate(Long id);
}

在StockMapper.xml中定義對應(yīng)的配置: ?

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 ? ? ? ?"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.distributedlock.mapper.StockMapper">
 ? ?<select id="selectStockForUpdate" 
resultType="com.atguigu.distributedlock.pojo.Stock">
 ? ? ? select * from db_stock where id = #{id} for update
 ? ?</select>
</mapper>

壓力測試

注意:測試之前,需要把庫存量改成5000。壓測數(shù)據(jù)如下:比jvm性能高很多,比無鎖要低將近1倍

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

mysql數(shù)據(jù)庫存:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

1.6.2. mysql樂觀鎖?

樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會造成沖突,所 以在數(shù)據(jù)進(jìn)行提交更新的時候,才會正式對數(shù)據(jù)的沖突與否進(jìn)行檢測,如果發(fā)現(xiàn)沖突了,則重試。那么 我們?nèi)绾螌?shí)現(xiàn)樂觀鎖呢?

使用數(shù)據(jù)版本(Version)記錄機(jī)制實(shí)現(xiàn),這是樂觀鎖最常用的實(shí)現(xiàn) 方式。一般是通過為數(shù)據(jù)庫表增加 一個數(shù)字類型的 “version” 字段來實(shí)現(xiàn)。當(dāng)讀取數(shù)據(jù)時,將version字段的值一同讀出,數(shù)據(jù)每更新一 次,對此version值加一。當(dāng)我們提交更新的時候,判斷數(shù)據(jù)庫表對應(yīng)記錄 的當(dāng)前版本信息與第一次取 出來的version值進(jìn)行比對,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的version值相等,則予以更新。

給db_stock表添加version字段:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

?對應(yīng)也需要給Stock實(shí)體類添加version屬性。此處略。

代碼實(shí)現(xiàn)

public void checkAndLock() {
 ? ?// 先查詢庫存是否充足
 ? ?Stock stock = this.stockMapper.selectById(1L);
 ? ?// 再減庫存
 ? ?if (stock != null && stock.getCount() > 0){
 ? ? ? ?// 獲取版本號
 ? ? ? ?Long version = stock.getVersion();
 ? ? ? ?stock.setCount(stock.getCount() - 1);
 ? ? ? ?// 每次更新 版本號 + 1
 ? ? ? ?stock.setVersion(stock.getVersion() + 1);
 ? ? ? ?// 更新之前先判斷是否是之前查詢的那個版本,如果不是重試
 ? ? ? ?if (this.stockMapper.update(stock, new UpdateWrapper<Stock>
().eq("id", stock.getId()).eq("version", version)) == 0) {
 ? ? ? ? ? ?checkAndLock();
 ? ? ? }
 ? }
}

?重啟后使用jmeter壓力測試工具結(jié)果如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

修改測試參數(shù)如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?測試結(jié)果如下:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

說明樂觀鎖在并發(fā)量越大的情況下,性能越低(因?yàn)樾枰罅康闹卦嚕?;并發(fā)量越小,性能越高。

?1.6.3. mysql鎖缺陷

在數(shù)據(jù)庫集群情況下會導(dǎo)致數(shù)據(jù)庫鎖失效,并且很多數(shù)據(jù)庫集群的中間件壓根就不支持悲觀鎖。例如:mycat,在讀寫分離的場景下可能會導(dǎo)致樂觀鎖不可靠。 這把鎖強(qiáng)依賴數(shù)據(jù)庫的可用性,數(shù)據(jù)庫是一個單點(diǎn),一旦數(shù)據(jù)庫掛掉,會導(dǎo)致業(yè)務(wù)系統(tǒng)不可用。

?2. 基于mysql實(shí)現(xiàn)分布式鎖

?不管是jvm鎖還是mysql鎖,為了保證線程的并發(fā)安全,都提供了悲觀獨(dú)占排他鎖。所以獨(dú)占排他也是 分布式鎖的基本要求。 可以利用唯一鍵索引不能重復(fù)插入的特點(diǎn)實(shí)現(xiàn)。設(shè)計(jì)表如下:

CREATE TABLE `db_lock` (
 ?`id` bigint(20) NOT NULL AUTO_INCREMENT,
 ?`lock_name` varchar(50) NOT NULL COMMENT '鎖名',
 ?`class_name` varchar(100) DEFAULT NULL COMMENT '類名',
 ?`method_name` varchar(50) DEFAULT NULL COMMENT '方法名',
 ?`server_name` varchar(50) DEFAULT NULL COMMENT '服務(wù)器ip',
 ?`thread_name` varchar(50) DEFAULT NULL COMMENT '線程名',
 ?`create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP 

COMMENT '獲取鎖時間',
 ?`desc` varchar(100) DEFAULT NULL COMMENT '描述',
 ?PRIMARY KEY (`id`),
 ?UNIQUE KEY `idx_unique` (`lock_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1332899824461455363 DEFAULT CHARSET=utf8;

Lock實(shí)體類: ?

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("db_lock")

public class Lock {
 ? ?private Long id;
 ? ?private String lockName;
 ? ?private String className;
 ? ?private String methodName;
 ? ?private String serverName;
 ? ?private String threadName;
 ? ?private Date createTime;
 ? ?private String desc;
}

LockMapper接口:

public interface LockMapper extends BaseMapper<Lock> {
}

2.1. 基本思路?

synchronized關(guān)鍵字和ReetrantLock鎖都是獨(dú)占排他鎖,即多個線程爭搶一個資源時,同一時刻只有 一個線程可以搶占該資源,其他線程只能阻塞等待,直到占有資源的線程釋放該資源。

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖

  1. 線程同時獲取鎖(insert)
  2. 獲取成功,執(zhí)行業(yè)務(wù)邏輯,執(zhí)行完成釋放鎖(delete)
  3. 其他線程等待重試

2.2. 代碼實(shí)現(xiàn)

改造StockService:

@Service

public class StockService {
 ? ?@Autowired
 ? ?private StockMapper stockMapper;
 ? ?@Autowired
 ? ?private LockMapper lockMapper;
 ? ?/**
 ? ? * 數(shù)據(jù)庫分布式鎖
 ? ? */
 ? ?public void checkAndLock() {
 ? ? ? ?// 加鎖
 ? ? ? ?Lock lock = new Lock(null, "lock", this.getClass().getName(), new 
Date(), null);
 ? ? ? ?try {
 ? ? ? ? ? ?this.lockMapper.insert(lock);
 ? ? ? } catch (Exception ex) {
 ? ? ? ? ? ?// 獲取鎖失敗,則重試
 ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ?Thread.sleep(50);
 ? ? ? ? ? ? ? ?this.checkAndLock();
 ? ? ? ? ? } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? }
 ? ? ? }
 ? ? ? ?// 先查詢庫存是否充足
 ? ? ? ?Stock stock = this.stockMapper.selectById(1L);
 ? ? ? ?// 再減庫存
 ? ? ? ?if (stock != null && stock.getCount() > 0){
 ? ? ? ? ? ?stock.setCount(stock.getCount() - 1);
 ? ? ? ? ? ?this.stockMapper.updateById(stock);
 ? ? ? }
 ? ? ? ?// 釋放鎖
 ? ? ? ?this.lockMapper.deleteById(lock.getId());
 ? }
}

加鎖: ?

// 加鎖
Lock lock = new Lock(null, "lock", this.getClass().getName(), new Date(), null);
try {
 ? ?this.lockMapper.insert(lock);
} catch (Exception ex) {
 ? ?// 獲取鎖失敗,則重試
 ? ?try {
 ? ? ? ?Thread.sleep(50);
 ? ? ? ?this.checkAndLock();
 ? } catch (InterruptedException e) {
 ? ? ? ?e.printStackTrace();
 ? }
}

解鎖:

// 釋放鎖
this.lockMapper.deleteById(lock.getId());

使用Jmeter壓力測試結(jié)果:

?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖?可以看到性能感人。mysql數(shù)據(jù)庫庫存余量為0,可以保證線程安全。?

2.3. 缺陷及解決方案?

1. 這把鎖強(qiáng)依賴數(shù)據(jù)庫的可用性,數(shù)據(jù)庫是一個單點(diǎn),一旦數(shù)據(jù)庫掛掉,會導(dǎo)致業(yè)務(wù)系統(tǒng)不可用。

解決方案:給鎖數(shù)據(jù)庫 搭建主備

2. 這把鎖沒有失效時間,一旦解鎖操作失敗,就會導(dǎo)致鎖記錄一直在數(shù)據(jù)庫中,其他線程無法再獲得到鎖。

解決方案:只要做一個定時任務(wù),每隔一定時間把數(shù)據(jù)庫中的超時數(shù)據(jù)清理一遍。

3. 這把鎖是非重入的,同一個線程在沒有釋放鎖之前無法再次獲得該鎖。因?yàn)閿?shù)據(jù)中數(shù)據(jù)已經(jīng)存在了。

解決方案:記錄獲取鎖的主機(jī)信息和線程信息,如果相同線程要獲取鎖,直接重入。

4. 受制于數(shù)據(jù)庫性能,并發(fā)能力有限。

解決方案:無法解決。文章來源地址http://www.zghlxwxcb.cn/news/detail-446493.html

到了這里,關(guān)于?【五一創(chuàng)作】基于mysql關(guān)系型實(shí)現(xiàn)分布式鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 一文帶你了解三大開源關(guān)系型數(shù)據(jù)庫:SQLite、MySQL和PostgreSQL

    一文帶你了解三大開源關(guān)系型數(shù)據(jù)庫:SQLite、MySQL和PostgreSQL

    目錄 1、概述 2、SQLite數(shù)據(jù)庫 2.1、SQLite簡介 2.2、SQLite優(yōu)缺點(diǎn) 2.3、SQLite應(yīng)用場景 3、MySQL數(shù)據(jù)庫 3.1、MySQL簡介 3.2、MySQL優(yōu)缺點(diǎn) 3.3、MySQL應(yīng)用場景 4、PostgreSQL數(shù)據(jù)庫 4.1、PostgreSQL簡介 4.2、PostgreSQL優(yōu)勢 4.3、PostgreSQL應(yīng)用場景 5、在實(shí)際系統(tǒng)中的選擇 VC++常用功能開發(fā)匯總(專欄文章列

    2024年02月08日
    瀏覽(126)
  • Sqlserver_Oracle_Mysql_Postgresql不同關(guān)系型數(shù)據(jù)庫之主從延遲的理解和實(shí)驗(yàn)

    關(guān)系型數(shù)據(jù)庫主從節(jié)點(diǎn)的延遲是否和隔離級別有關(guān)聯(lián),個人認(rèn)為兩者沒有直接關(guān)系,主從延遲在關(guān)系型數(shù)據(jù)庫中一般和這兩個時間有關(guān):事務(wù)日志從主節(jié)點(diǎn)傳輸?shù)綇墓?jié)點(diǎn)的時間+事務(wù)日志在從節(jié)點(diǎn)的應(yīng)用時間 事務(wù)日志從主節(jié)點(diǎn)傳輸?shù)綇墓?jié)點(diǎn)的時間,相關(guān)因素有以下2點(diǎn): 1、事

    2024年02月14日
    瀏覽(24)
  • 使用Kepserver 自帶 DataLogger 功能 實(shí)現(xiàn)工控?cái)?shù)據(jù)轉(zhuǎn)儲關(guān)系型數(shù)據(jù)庫

    使用Kepserver 自帶 DataLogger 功能 實(shí)現(xiàn)工控?cái)?shù)據(jù)轉(zhuǎn)儲關(guān)系型數(shù)據(jù)庫

    本文以 Mysql數(shù)據(jù)庫為例,介紹使用 kepserver 的datalogger 功能轉(zhuǎn)儲數(shù)據(jù)到 mysql 第一步:下載安裝 Mysql ODBC 數(shù)據(jù)庫驅(qū)動 前往 官網(wǎng)下載ODBC驅(qū)動 https://downloads.MySQL.com/archives/c-ODBC/ 建議下載 msi 格式的安裝文件? ?下載完成后,直接安裝。 如果安裝過程報(bào)這個錯,那就下載個 vc_redist?

    2024年02月02日
    瀏覽(21)
  • Redis基于內(nèi)存的key-value結(jié)構(gòu)化NOSQL(非關(guān)系型)數(shù)據(jù)庫

    Redis基于內(nèi)存的key-value結(jié)構(gòu)化NOSQL(非關(guān)系型)數(shù)據(jù)庫

    Redis基于內(nèi)存的key-value結(jié)構(gòu)的NOSQL(非關(guān)系型)數(shù)據(jù)庫 非關(guān)系型數(shù)據(jù)庫:表與表之間沒有復(fù)雜的關(guān)系 基于內(nèi)存存儲,讀寫性能高 – Redis讀的速度是110000次/S 適合存儲熱點(diǎn)數(shù)據(jù)(商品、新聞資訊) 它存儲的value類型比較豐富,也稱為結(jié)構(gòu)化NoSQL數(shù)據(jù)庫 直接解壓windows版壓縮包就

    2024年02月11日
    瀏覽(35)
  • 關(guān)系型和非關(guān)系型數(shù)據(jù)庫的區(qū)別

    關(guān)系型數(shù)據(jù)庫,是指采用了關(guān)系模型來組織數(shù)據(jù)的數(shù)據(jù)庫,關(guān)系型數(shù)據(jù)庫的最大特點(diǎn)就是事務(wù)的一致性。關(guān)系型數(shù)據(jù)天然就是表格式的,因此數(shù)據(jù)存儲在數(shù)據(jù)表的行和列中。數(shù)據(jù)表可以彼此關(guān)聯(lián)協(xié)作存儲,也很容易提取數(shù)據(jù)。 優(yōu)點(diǎn) 易于維護(hù):都是使用表結(jié)構(gòu),格式一致。 使

    2024年02月13日
    瀏覽(27)
  • 關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫

    關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫

    ?關(guān)系型數(shù)據(jù)庫是以 關(guān)系(表格) 為基礎(chǔ)的數(shù)據(jù)庫,它采用了 SQL(Structured Query Language)作為數(shù)據(jù)操作語言,常見的關(guān)系型數(shù)據(jù)庫包括 MySQL、Oracle、SQL Server 等。 非關(guān)系型數(shù)據(jù)庫則是基于 文檔、鍵值、列族 等方式存儲數(shù)據(jù)的數(shù)據(jù)庫,它通常沒有固定的表結(jié)構(gòu),因此也被稱為

    2024年02月09日
    瀏覽(27)
  • 關(guān)系型數(shù)據(jù)庫與非關(guān)系型數(shù)據(jù)庫類比

    關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫都有多種不同類型,每種類型都針對不同的數(shù)據(jù)存儲需求和使用場景。以下是一些常見的關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫類型: 關(guān)系型數(shù)據(jù)庫類型: MySQL: 一種開源的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),用于處理結(jié)構(gòu)化數(shù)據(jù),適用于各種規(guī)模的應(yīng)用。

    2024年02月11日
    瀏覽(27)
  • 關(guān)系型非關(guān)系型數(shù)據(jù)庫區(qū)別,以MongoDB為例在express中連接MongoDB示例

    目錄 關(guān)系型數(shù)據(jù)庫 關(guān)系型數(shù)據(jù)庫常見的類型有: 關(guān)系型數(shù)據(jù)庫的優(yōu)點(diǎn)包括: 非關(guān)系型數(shù)據(jù)庫 非關(guān)系型數(shù)據(jù)庫常見的類型有: 非關(guān)系型數(shù)據(jù)庫的特點(diǎn)包括: 關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫區(qū)別 MongoDB是什么 MongoDB優(yōu)勢: 在Express中連接MongoDB步驟 Schema 關(guān)系型數(shù)據(jù)庫是以關(guān)系模

    2024年01月16日
    瀏覽(30)
  • 關(guān)系型數(shù)據(jù)庫設(shè)計(jì)

    關(guān)系型數(shù)據(jù)庫設(shè)計(jì)

    目錄 1.數(shù)據(jù)庫設(shè)計(jì)的重要性及定義 1.1 數(shù)據(jù)庫設(shè)計(jì)的重要性 1.1.1 失敗的數(shù)據(jù)庫設(shè)計(jì)造成的后果? 1.1.2?優(yōu)秀的數(shù)據(jù)庫設(shè)計(jì)帶來的好處? 1.2?數(shù)據(jù)庫設(shè)計(jì)的定義? 2.數(shù)據(jù)庫需求分析? 2.1?需求分析的步驟 2.1.1 收集信息 2.1.2?標(biāo)識實(shí)體 2.1.3?標(biāo)識每個實(shí)體的詳細(xì)信息? 2.1.4?標(biāo)識實(shí)體之

    2024年04月10日
    瀏覽(28)
  • 非關(guān)系型數(shù)據(jù)庫

    一、什么是非關(guān)系型數(shù)據(jù)庫? 隨著互聯(lián)網(wǎng)的飛速發(fā)展,人們對數(shù)據(jù)存儲和管理的需求越來越高,傳統(tǒng)的關(guān)系型數(shù)據(jù)庫遇到了越來越多的挑戰(zhàn)。為了滿足海量數(shù)據(jù)存儲和高性能查詢的需求,非關(guān)系型數(shù)據(jù)庫(NoSQL)應(yīng)運(yùn)而生。 非關(guān)系型數(shù)據(jù)庫是指不使用關(guān)系模型進(jìn)行數(shù)據(jù)組織和

    2024年02月07日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包