国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

新公司網(wǎng)站建設(shè)百度平臺(tái)營銷收費(fèi)標(biāo)準(zhǔn)

新公司網(wǎng)站建設(shè),百度平臺(tái)營銷收費(fèi)標(biāo)準(zhǔn),民治做網(wǎng)站的公司,工程服務(wù)建設(shè)網(wǎng)站一、MySQL 排它鎖和共享鎖 在進(jìn)行實(shí)驗(yàn)前,先來了解下MySQL 的排它鎖和共享鎖,在 MySQL 中的鎖分為表鎖和行鎖,在行鎖中鎖又分成了排它鎖和共享鎖兩種類型。 1. 排它鎖 排他鎖又稱為寫鎖,簡稱X鎖,是一種悲觀鎖&#x…

一、MySQL 排它鎖和共享鎖

在進(jìn)行實(shí)驗(yàn)前,先來了解下MySQL 的排它鎖和共享鎖,在 MySQL 中的鎖分為表鎖和行鎖,在行鎖中鎖又分成了排它鎖和共享鎖兩種類型。

1. 排它鎖

排他鎖又稱為寫鎖,簡稱X鎖,是一種悲觀鎖,具有悲觀鎖的特征,如一個(gè)事務(wù)獲取了一個(gè)數(shù)據(jù)行的X鎖,其他事務(wù)嘗試獲取鎖時(shí)就會(huì)等待另一個(gè)事務(wù)的釋放。其中在 InnoDB 引擎下做寫操作時(shí) (UPDATE、DELETE、INSERT)都會(huì)自動(dòng)給涉及到的數(shù)據(jù)加上 X 鎖,因此當(dāng)多線程情況下對(duì)同一條數(shù)據(jù)進(jìn)行更新,在MySQL中不會(huì)出現(xiàn)線程安全問題。

其中 SELECT 語句默認(rèn)不會(huì)加鎖,如果查詢的數(shù)據(jù)已經(jīng)存在 X 鎖,則會(huì)返回其最近提交的數(shù)據(jù),如果希望每次獲取的數(shù)據(jù)都是更新后最新的數(shù)據(jù),當(dāng)存在有更新時(shí),則等待更新完成后獲取新的值,這種情況下就需要對(duì) SELECT 語句也要存在 X 鎖,其中 SELECT 語句加 X 鎖的話需要使用 FOR UPDATE 語句。

比如:當(dāng)前有一張表結(jié)構(gòu)如下:

CREATE TABLE `lock` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

寫入一條測(cè)試數(shù)據(jù):

INSERT INTO `testdb`.`lock`(`id`, `name`) VALUES (1, 'lock1');

下面,我使用 Navicat 開啟了兩個(gè)對(duì)話框,我在第一個(gè)對(duì)話框中,使用手動(dòng)提交事務(wù)的方式執(zhí)行更新語句,并且既不提交也不回滾事務(wù):

BEGIN;
UPDATE `lock` SET `name` = 'lock2' WHERE id = 1; 

在這里插入圖片描述
下面在另一個(gè)對(duì)話框中,查詢 id = 1 的數(shù)據(jù):

SELECT * FROM `lock` where id = 1

在這里插入圖片描述
可以看到,并沒有拿到最新的內(nèi)容,因?yàn)榇藭r(shí) X 鎖還沒有釋放,那此時(shí)對(duì)查詢語句進(jìn)行調(diào)整下,加上 FOR UPDATE 語句:

SELECT * FROM `lock` where id = 1 FOR UPDATE

在這里插入圖片描述

此時(shí)會(huì)發(fā)現(xiàn),查詢語句一直在等待,因?yàn)檫@個(gè)查詢語句在等待 X 鎖的釋放,下面對(duì)第一個(gè)對(duì)話框中,執(zhí)行提交事務(wù):

COMMIT;

在這里插入圖片描述
在回到第二個(gè)對(duì)話框中查看:
在這里插入圖片描述
已經(jīng)拿到最新的值。這里需要注意下,你的是不是出現(xiàn)了超時(shí)報(bào)錯(cuò),這是因?yàn)?Innodb 引擎對(duì)等待鎖有個(gè)等待超時(shí)時(shí)間,默認(rèn)情況下是 50s ,可以通過下面指令查看:

SHOW VARIABLES LIKE "Innodb_lock_wait_timeout"

在這里插入圖片描述

如果感覺太小,可以通過下面指令調(diào)整:

SET innodb_lock_wait_timeout = 100

上面的操作已經(jīng)感覺出來 X 鎖的效果,那當(dāng)兩個(gè) SELECT 語句都加上 FOR UPDATE 呢,比如在第一個(gè)回話框中,使用手動(dòng)事務(wù)執(zhí)行 SELECT 語句,同樣不提交事務(wù):

BEGIN;
SELECT * FROM `lock` where id = 1 FOR UPDATE;

在這里插入圖片描述

在第二個(gè)對(duì)話框同樣執(zhí)行相同的代碼,可以發(fā)現(xiàn)被阻塞掉了。

在這里插入圖片描述

當(dāng)?shù)谝粋€(gè)提交事務(wù)后,第二個(gè)緊接著也查出了信息,這也正符合排他鎖的特征。

2. 共享鎖

共享鎖可以理解為讀鎖,簡稱S鎖,可以對(duì)多個(gè)事務(wù)SELECT情況下讀取同一數(shù)據(jù)時(shí)不會(huì)阻塞,但是如果存在寫操作時(shí) (UPDATE、DELETE、INSERT),SELECT語句也會(huì)被阻塞,在MySQL中使用 S 鎖需要使用 LOCK IN SHARE MODE。

例如還是開啟兩個(gè)對(duì)話框,在第兩個(gè)對(duì)話框中,都查詢 id = 1 的數(shù)據(jù),并加上 S 鎖,最后同樣不提交事務(wù):

BEGIN;
SELECT * FROM `lock` where id = 1 LOCK IN SHARE MODE;

在這里插入圖片描述
可以發(fā)現(xiàn)兩個(gè)都拿到了數(shù)據(jù),對(duì)兩個(gè)都提交事務(wù)后,假如第一個(gè)對(duì)話框中是更新操作,最后同樣不提交事務(wù):

BEGIN;
UPDATE `lock` SET `name` = 'lock3' WHERE id = 1 ;

在這里插入圖片描述
在第二個(gè)對(duì)話框中還是加上 S 鎖的查詢操作:

BEGIN;
SELECT * FROM `lock` where id = 1 LOCK IN SHARE MODE;

在這里插入圖片描述

可以看到查詢被阻塞了,當(dāng)?shù)谝粋€(gè)對(duì)話框中提交了事務(wù),這里才會(huì)返回結(jié)果:

在這里插入圖片描述
讀到這里相信大家已經(jīng)對(duì) MySQL 的排它鎖和共享鎖有了一定的了解,下面我們基于 排它鎖 實(shí)現(xiàn)分布式鎖的場(chǎng)景。

二、基于 MySQL 排它鎖實(shí)現(xiàn)分布式可重入鎖

根據(jù)上面的實(shí)例可以看到排它鎖具有阻塞等待的效果,和我們 JVM 中普通的鎖的效果是一致的,但普通的鎖通常只能在單個(gè) JVM 中,但現(xiàn)在的服務(wù),動(dòng)則都要多臺(tái)集群部署,對(duì)于不同的 JVM 普通的鎖實(shí)在心有余而力不足,此時(shí)就要考慮使用分布式鎖,目前分布式鎖的解決方案也比較多,例如基于 RedissetNx 實(shí)現(xiàn)的分布式鎖,相關(guān)框架有 Redissson ,還有基于 Zookeeper 的臨時(shí)節(jié)點(diǎn)實(shí)現(xiàn)的分布式鎖,相關(guān)框架有 Curator 等等,而且這些都有方案實(shí)現(xiàn)鎖的可重入性。

本文我們?cè)俳榻B一種基于 MySQL 的方案,畢竟現(xiàn)在再小的項(xiàng)目基本都會(huì)引入數(shù)據(jù)庫,我們?cè)诖嘶A(chǔ)上延伸也少了其他框架的學(xué)習(xí)。

實(shí)現(xiàn)的思路:

  1. 數(shù)據(jù)庫中創(chuàng)建一個(gè)lock 表 ,里面根據(jù)場(chǎng)景添加數(shù)據(jù),一行就代表一個(gè)分布式鎖的句柄。
  2. 在項(xiàng)目中在需要鎖的方法中首先開啟事務(wù),保證下面的操作在事務(wù)中,事務(wù)可借助 Spring@Transactional 注解。
  3. 在獲取鎖時(shí),使用 SELECT * FROM lock WHERE id = #{id} FOR UPDATE 排它鎖語句執(zhí)行。
  4. 如果正常查詢到則獲取鎖成功,此時(shí)如果其他事務(wù)也在獲取鎖,則因?yàn)榕潘i的原因會(huì)阻塞等待。
  5. 此時(shí)如果還要獲取鎖,也就是對(duì)于鎖的可重入性設(shè)計(jì),可以利用同一個(gè)事務(wù)中對(duì)于同一條數(shù)據(jù) FOR UPDATE 不會(huì)阻塞的特征,只需在同一個(gè)事務(wù)中再次獲取鎖的操作即可實(shí)現(xiàn) 。
  6. 方法執(zhí)行完,如果是手動(dòng)事務(wù)一定要提交或回滾事務(wù),即表示釋放鎖,如果是 Spring@Transactional 注解,則會(huì)自動(dòng)提交或回滾。

開始實(shí)施:

首先新建一個(gè) SpringBoot 項(xiàng)目,在 pom 中引入 mybatis-plus 依賴:

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.2</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.6</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

下面在配置文件中增加 MySQL 的配置:

server:port: 8081spring:datasource:url: jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf8&serverTimezone=UTCusername: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSource

下面獲取鎖的邏輯其實(shí)就是一個(gè) Mapper 中的 Select 操作:

@Mapper
public interface LockMapper {/*** 嘗試獲取鎖*/@Select("SELECT id FROM `lock` where id = #{id} FOR UPDATE;")Long tryLock(@Param("id") Long id);
}

下面編寫一個(gè)線程安全的例子,使用 10 個(gè)線程,去對(duì)一個(gè)全局 int 變量做 +1 操作,這里為了方便測(cè)試,直接聲明成 Controller

@RestController
public class LockService {private volatile int count = 0;@GetMapping("/test")public void test() {for (int i = 0; i < 10; i++) {new Thread(() -> {testLock();}).start();}}public void testLock() {count++;System.out.print(count+" , ");}
}

運(yùn)行后,訪問測(cè)試接口,查看控制臺(tái)打印的效果:
在這里插入圖片描述
可以看到已經(jīng)出現(xiàn)線程安全問題了,下面我們改造成使用 MySQL 的排他鎖進(jìn)行協(xié)調(diào),這里需要注意下,這里事務(wù)使用的是 Spring@Transactional 注解,是基于 AOP 實(shí)現(xiàn)的,因此 LockService 需要從 Spring 容器中獲取 ,另外對(duì)于鎖的超時(shí)可以捕獲 CannotAcquireLockException 異常。

@RestController
public class LockService {@ResourceLockService lockService;@ResourceLockMapper lockMapper;private final Long LOCK_ID = 1L;private volatile int count = 0;@GetMapping("/test")public void test() {for (int i = 0; i < 10; i++) {new Thread(() -> {lockService.testLock();}).start();}}@Transactional(rollbackFor = Exception.class)public void testLock() {try {//獲取鎖,如果獲取不到則阻塞if (Objects.nonNull(lockMapper.tryLock(LOCK_ID))){count++;System.out.print(count + " , ");}} catch (CannotAcquireLockException e) {System.out.println("獲取鎖超時(shí)!");}}
}

執(zhí)行后,查看日志:

在這里插入圖片描述
細(xì)心地話可以明顯感覺執(zhí)行速度比之前慢了,因?yàn)槌霈F(xiàn)了阻塞情況,通過數(shù)據(jù)可以看到已經(jīng)解決了線程安全問題,但是鎖的可重入性呢,我們?cè)讷@取到鎖后,再次獲取鎖看看是否正常,注意可重入鎖表示鎖中鎖,鎖的對(duì)象一定要是一致的,也就是這里的鎖的 ID 要是一致的:

@RestController
public class LockService {@ResourceLockService lockService;@ResourceLockMapper lockMapper;private final Long LOCK_ID = 1L;private volatile int count = 0;@GetMapping("/test")public void test() {for (int i = 0; i < 10; i++) {new Thread(() -> {lockService.testLock();}).start();}}@Transactional(rollbackFor = Exception.class)public void testLock() {try {//獲取鎖,如果獲取不到則阻塞if (Objects.nonNull(lockMapper.tryLock(LOCK_ID))){// 重入鎖if (Objects.nonNull(lockMapper.tryLock(LOCK_ID))){count++;System.out.print(count + " , ");}}} catch (CannotAcquireLockException e) {System.out.println("獲取鎖超時(shí)!");}}
}

運(yùn)行后,查看日志:

在這里插入圖片描述
可以看到可重入鎖場(chǎng)景下也是可以正常獲取到鎖。

三、總結(jié)

本文基于 MySQL 實(shí)現(xiàn)的一種分布式可重入鎖的效果,由于鎖是使用的 MySQL 的排他鎖,因此在多個(gè) JVM 中也是可以實(shí)現(xiàn)鎖的效果。這里主要講解了實(shí)現(xiàn)思路,對(duì)于模塊的封裝沒有做過多的設(shè)計(jì),如果有想法的小伙伴也可以發(fā)動(dòng)想法封裝一下。另外由于是使用了 MySQL 如果是大量并發(fā)的情況下,可能會(huì)對(duì) MySQL 造成一些壓力。另外可能由于某些原因造成一端持有鎖的時(shí)間過長,其余等待鎖發(fā)生超時(shí)現(xiàn)象,超時(shí)情況這里未做處理,后續(xù)可以根據(jù)實(shí)際情況進(jìn)行重試或錯(cuò)誤處理。

http://m.aloenet.com.cn/news/42596.html

相關(guān)文章:

  • 網(wǎng)站開發(fā)電商快速網(wǎng)站推廣優(yōu)化
  • 濰坊百度網(wǎng)站建設(shè)產(chǎn)品推廣圖片
  • 內(nèi)銷機(jī)械做哪個(gè)網(wǎng)站好開發(fā)新客戶的十大渠道
  • 沈陽建信建設(shè)工程有限公司位置seo關(guān)鍵詞排名網(wǎng)絡(luò)公司
  • 企業(yè)網(wǎng)站banner尺寸小紅書外鏈管家
  • wordpress短視頻模板紹興seo
  • 網(wǎng)站開發(fā)成本核算杭州seo公司哪家好
  • 網(wǎng)站模板 尋模板百度競(jìng)價(jià)開戶費(fèi)用
  • 嬰幼兒網(wǎng)站模板鎮(zhèn)江百度推廣公司
  • 巨野網(wǎng)站建設(shè)百度云搜索引擎 百度網(wǎng)盤
  • 做網(wǎng)站想注冊(cè)商標(biāo)是哪一類百度公司總部在哪里
  • 專業(yè)制作公司網(wǎng)站公司百度一下首頁下載安裝桌面
  • 下載住小幫app看裝修seo排名優(yōu)化代理
  • 百度搜索網(wǎng)站怎么做策劃網(wǎng)絡(luò)營銷活動(dòng)
  • 校園網(wǎng)站開發(fā)背景淘寶seo關(guān)鍵詞的獲取方法有哪些
  • 織夢(mèng)網(wǎng)站+當(dāng)前位置限制寬度市場(chǎng)調(diào)研的內(nèi)容
  • 石家莊抖音代運(yùn)營公司網(wǎng)站seo規(guī)劃
  • 外貿(mào)網(wǎng)站建設(shè)模板培訓(xùn)班招生方案
  • 我是做裝修的怎么樣投資網(wǎng)站百度天眼查
  • 做app和做網(wǎng)站區(qū)別常用網(wǎng)站推廣方法及資源
  • 做網(wǎng)站怎樣使圖片自由移動(dòng)制作app軟件平臺(tái)
  • 手機(jī)怎么建立微信公眾號(hào)贛州seo公司
  • 學(xué)校門戶網(wǎng)站建設(shè)研究綜述app推廣團(tuán)隊(duì)
  • 福田附近公司做網(wǎng)站建設(shè)哪家效益快seo教程下載
  • wordpress政府門戶網(wǎng)站西安百度代運(yùn)營
  • 女生做網(wǎng)站開發(fā)推廣途徑有哪些
  • 泉州哪里有搭建網(wǎng)站的公司寧波seo推廣服務(wù)電話
  • 做a 需要制作網(wǎng)站網(wǎng)絡(luò)營銷的整體概念
  • 網(wǎng)站建設(shè)掙錢嗎?怎么自己做網(wǎng)頁
  • 網(wǎng)站引導(dǎo)動(dòng)畫怎么做的邯鄲百度推廣公司