女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

數據庫的樂觀鎖和悲觀鎖的使用場景

電子工程師 ? 來源:ZYD ? 2019-02-25 11:04 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在寫入數據庫的時候需要有鎖,比如同時寫入數據庫的時候會出現丟數據,那么就需要鎖機制。

數據鎖分為樂觀鎖和悲觀鎖

它們使用的場景如下:

樂觀鎖適用于寫少讀多的情景,因為這種樂觀鎖相當于JAVA的CAS,所以多條數據同時過來的時候,不用等待,可以立即進行返回。

悲觀鎖適用于寫多讀少的情景,這種情況也相當于JAVA的synchronized,reentrantLock等,大量數據過來的時候,只有一條數據可以被寫入,其他的數據需要等待。執行完成后下一條數據可以繼續。

他們實現的方式上有所不同。

樂觀鎖采用版本號的方式,即當前版本號如果對應上了就可以寫入數據,如果判斷當前版本號不一致,那么就不會更新成功,

比如

update table set column = value

where version=${version} and otherKey = ${otherKey}

悲觀鎖實現的機制一般是在執行更新語句的時候采用for update方式,

比如

update table set column='value'for update

這種情況where條件呢一定要涉及到數據庫對應的索引字段,這樣才會是行級鎖,否則會是表鎖,這樣執行速度會變慢。

下面我就弄一個spring boot(springboot 2.1.1 + mysql + lombok + aop + jpa)工程,然后逐漸的實現樂觀鎖和悲觀鎖。

假設有一個場景,有一個catalog商品目錄表,然后還有一個browse瀏覽表,假如一個商品被瀏覽了,那么就需要記錄下瀏覽的user是誰,并且記錄訪問的總數。

表的結構非常簡單:

create table catalog (

id int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',

name varchar(50) NOT NULL DEFAULT '' COMMENT '商品名稱',

browse_count int(11) NOT NULL DEFAULT 0 COMMENT '瀏覽數',

version int(11) NOT NULL DEFAULT 0 COMMENT '樂觀鎖,版本號',

PRIMARY KEY(id)

) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE table browse (

id int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',

cata_id int(11) NOT NULL COMMENT '商品ID',

user varchar(50) NOT NULL DEFAULT '' COMMENT '',

create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '創建時間',

PRIMARY KEY(id)

) ENGINE=INNODB DEFAULT CHARSET=utf8;

POM.XML的依賴如下:

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.1.1.RELEASE

com.hqs

dblock

1.0-SNAPSHOT

dblock

Demo project for Spring Boot

1.8

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-devtools

runtime

mysql

mysql-connector-java

runtime

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-starter-data-jpa

mysql

mysql-connector-java

org.projectlombok

lombok

true

org.aspectj

aspectjweaver

1.8.4

org.springframework.boot

spring-boot-maven-plugin

項目的結構如下:

介紹一下項目的結構的內容:

entity包: 實體類包。

repository包:數據庫repository

service包: 提供服務的service

controller包: 控制器寫入用于編寫requestMapping。相關請求的入口類

annotation包: 自定義注解,用于重試。

aspect包: 用于對自定義注解進行切面。

DblockApplication: springboot的啟動類。

DblockApplicationTests: 測試類。

咱們看一下核心代碼的實現,參考如下,使用dataJpa非常方便,集成了CrudRepository就可以實現簡單的CRUD,非常方便,有興趣的同學可以自行研究。

實現樂觀鎖的方式有兩種:

1、更新的時候將version字段傳過來,然后更新的時候就可以進行version判斷,如果version可以匹配上,那么就可以更新(方法:updateCatalogWithVersion)。

2、在實體類上的version字段上加入version,可以不用自己寫SQL語句就可以它就可以自行的按照version匹配和更新,是不是很簡單。

publicinterfaceCatalogRepositoryextendsCrudRepository {

@Query(value = "select * from Catalog a where a.id = :id for update", nativeQuery = true)

Optional findCatalogsForUpdate(@Param("id") Long id);

@Lock(value = LockModeType.PESSIMISTIC_WRITE) //代表行級鎖

@Query("select a from Catalog a where a.id = :id")

Optional findCatalogWithPessimisticLock(@Param("id") Long id);

@Modifying(clearAutomatically = true) //修改時需要帶上

@Query(value = "update Catalog set browse_count = :browseCount, version = version + 1 where id = :id " +

"and version = :version", nativeQuery = true)

int updateCatalogWithVersion(@Param("id") Long id, @Param("browseCount") Long browseCount, @Param("version") Long version);

}

實現悲觀鎖的時候也有兩種方式:

1、自行寫原生SQL,然后寫上for update語句。(方法:findCatalogsForUpdate)

2、使用@Lock注解,并且設置值為LockModeType.PESSIMISTIC_WRITE即可代表行級鎖。

還有我寫的測試類,方便大家進行測試:

package com.hqs.dblock;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.boot.test.web.client.TestRestTemplate;

import org.springframework.test.context.junit4.SpringRunner;

import org.springframework.util.LinkedMultiValueMap;

import org.springframework.util.MultiValueMap;

@RunWith(SpringRunner.class)

@SpringBootTest(classes = DblockApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

publicclassDblockApplicationTests {

@Autowired

privateTestRestTemplate testRestTemplate;

@Test

publicvoid browseCatalogTest() {

String url = "http://localhost:8888/catalog";

for(int i = 0; i < 100; i++) {

finalint num = i;

newThread(() -> {

MultiValueMap params = newLinkedMultiValueMap<>();

params.add("catalogId", "1");

params.add("user", "user" + num);

String result = testRestTemplate.postForObject(url, params, String.class);

System.out.println("-------------" + result);

}

).start();

}

}

@Test

publicvoid browseCatalogTestRetry() {

String url = "http://localhost:8888/catalogRetry";

for(int i = 0; i < 100; i++) {

finalint num = i;

newThread(() -> {

MultiValueMap params = newLinkedMultiValueMap<>();

params.add("catalogId", "1");

params.add("user", "user" + num);

String result = testRestTemplate.postForObject(url, params, String.class);

System.out.println("-------------" + result);

}

).start();

}

}

}

調用100次,即一個商品可以瀏覽一百次,采用悲觀鎖,catalog表的數據都是100,并且browse表也是100條記錄。采用樂觀鎖的時候,因為版本號的匹配關系,那么會有一些記錄丟失,但是這兩個表的數據是可以對應上的。

樂觀鎖失敗后會拋出ObjectOptimisticLockingFailureException,那么我們就針對這塊考慮一下重試,下面我就自定義了一個注解,用于做切面。

package com.hqs.dblock.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public@interfaceRetryOnFailure {

}

針對注解進行切面,見如下代碼。我設置了最大重試次數5,然后超過5次后就不再重試。

package com.hqs.dblock.aspect;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.hibernate.StaleObjectStateException;

import org.springframework.orm.ObjectOptimisticLockingFailureException;

import org.springframework.stereotype.Component;

@Slf4j

@Aspect

@Component

publicclassRetryAspect {

publicstaticfinalint MAX_RETRY_TIMES = 5;//max retry times

@Pointcut("@annotation(com.hqs.dblock.annotation.RetryOnFailure)") //self-defined pointcount for RetryOnFailure

publicvoid retryOnFailure(){}

@Around("retryOnFailure()") //around can be execute before and after the point

publicObject doConcurrentOperation(ProceedingJoinPoint pjp) throwsThrowable {

int attempts = 0;

do {

attempts++;

try {

pjp.proceed();

} catch (Exception e) {

if(e instanceofObjectOptimisticLockingFailureException ||

e instanceofStaleObjectStateException) {

log.info("retrying....times:{}", attempts);

if(attempts > MAX_RETRY_TIMES) {

log.info("retry excceed the max times..");

throw e;

}

}

}

} while (attempts < MAX_RETRY_TIMES);

returnnull;

}

}

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據庫
    +關注

    關注

    7

    文章

    3926

    瀏覽量

    66194

原文標題:聊聊數據庫樂觀鎖和悲觀鎖

文章出處:【微信號:DBDevs,微信公眾號:數據分析與開發】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    milvus向量數據庫的主要特性和應用場景

    Milvus 是一個開源的向量數據庫,專門為處理和分析大規模向量數據而設計。它適用于需要高效存儲、檢索和管理向量數據的應用場景,如機器學習、人工智能、計算機視覺和自然語言處理等。
    的頭像 發表于 07-04 11:36 ?185次閱讀
    milvus向量<b class='flag-5'>數據庫</b>的主要特性和應<b class='flag-5'>用場景</b>

    數據庫數據恢復—SQL Server數據庫被加密如何恢復數據

    SQL Server數據庫故障: SQL Server數據庫被加密,無法使用。 數據庫MDF、LDF、log日志文件名字被篡改。
    的頭像 發表于 06-25 13:54 ?138次閱讀
    <b class='flag-5'>數據庫</b><b class='flag-5'>數據</b>恢復—SQL Server<b class='flag-5'>數據庫</b>被加密如何恢復<b class='flag-5'>數據</b>?

    一文讀懂Allegro先進磁性開關和存器

    Allegro 擁有豐富的霍爾效應和隧道磁阻(TMR)開關及存器產品,可廣泛應用于汽車、工業和消費電子等領域。本應用筆記旨在提供分步選型流程,協助設計師為具體應用場景選擇適配的 Allegro
    的頭像 發表于 06-12 17:26 ?675次閱讀
    一文讀懂Allegro先進磁性開關和<b class='flag-5'>鎖</b>存器

    MySQL數據庫是什么

    開發、企業應用和大數據場景。以下是其核心特性和應用場景的詳細說明: 核心特性 關系型數據庫模型 數據以 表(Table) 形式組織,表由行(
    的頭像 發表于 05-23 09:18 ?435次閱讀

    電路模組選擇指南

    。要解除自,通常需要一個額外的信號來使觸點斷開。 2. 自電路模組的類型 自電路模組可以根據不同的應用場景和需求選擇不同類型的繼電器: 電磁繼電器 :最傳統的自
    的頭像 發表于 01-18 10:08 ?629次閱讀

    電路的類型和特點

    和應用場景分為以下幾種類型: 機械式自電路 : 這種類型的自電路依賴于機械裝置來保持電路的狀態。例如,一個簡單的開關可以設計成在按下后自動鎖定,直到再次按下才會釋放。 電子式自
    的頭像 發表于 01-18 10:03 ?909次閱讀

    MySQL數據庫的安裝

    MySQL數據庫的安裝 【一】各種數據庫的端口 MySQL :3306 Redis :6379 MongoDB :27017 Django :8000 flask :5000 【二】MySQL 介紹
    的頭像 發表于 01-14 11:25 ?562次閱讀
    MySQL<b class='flag-5'>數據庫</b>的安裝

    數據庫是哪種數據庫類型?

    數據庫是一種部署在虛擬計算環境中的數據庫,它融合了云計算的彈性和可擴展性,為用戶提供高效、靈活的數據庫服務。云數據庫主要分為兩大類:關系型數據庫
    的頭像 發表于 01-07 10:22 ?507次閱讀

    數據庫數據恢復—Mysql數據庫表記錄丟失的數據恢復流程

    Mysql數據庫故障: Mysql數據庫表記錄丟失。 Mysql數據庫故障表現: 1、Mysql數據庫表中無任何數據或只有部分
    的頭像 發表于 12-16 11:05 ?606次閱讀
    <b class='flag-5'>數據庫</b><b class='flag-5'>數據</b>恢復—Mysql<b class='flag-5'>數據庫</b>表記錄丟失的<b class='flag-5'>數據</b>恢復流程

    數據庫數據恢復—MYSQL數據庫ibdata1文件損壞的數據恢復案例

    mysql數據庫故障: mysql數據庫文件ibdata1、MYI、MYD損壞。 故障表現:1、數據庫無法進行查詢等操作;2、使用mysqlcheck和myisamchk無法修復數據庫
    的頭像 發表于 12-09 11:05 ?632次閱讀

    有單通道數據存模塊嗎?

    請問,有單通道數據存模塊嗎?應用是系統網電斷電后,任然可以數據狀態。要求存模塊能長期單獨長期供電。
    發表于 11-13 07:42

    多維表格數據庫Teable的適用場景

    Teable多維表格數據庫是一款功能強大的云端數據庫和協作工具,結合了電子表格的靈活性和數據庫的強大功能,適用企業內部項目管理 數據收集與整理 內容管理與創意協作 客戶關系管理 項目跟
    的頭像 發表于 10-31 15:48 ?849次閱讀

    數據庫數據恢復—通過拼接數據庫碎片恢復SQLserver數據庫

    一個運行在存儲上的SQLServer數據庫,有1000多個文件,大小幾十TB。數據庫每10天生成一個NDF文件,每個NDF幾百GB大小。數據庫包含兩個LDF文件。 存儲損壞,數據庫
    的頭像 發表于 10-31 13:21 ?695次閱讀
    <b class='flag-5'>數據庫</b><b class='flag-5'>數據</b>恢復—通過拼接<b class='flag-5'>數據庫</b>碎片恢復SQLserver<b class='flag-5'>數據庫</b>

    數據庫數據恢復—SQL Server數據庫出現823錯誤的數據恢復案例

    SQL Server數據庫故障: SQL Server附加數據庫出現錯誤823,附加數據庫失敗。數據庫沒有備份,無法通過備份恢復數據庫
    的頭像 發表于 09-20 11:46 ?700次閱讀
    <b class='flag-5'>數據庫</b><b class='flag-5'>數據</b>恢復—SQL Server<b class='flag-5'>數據庫</b>出現823錯誤的<b class='flag-5'>數據</b>恢復案例

    存器電路中的中間是什么元件

    的主要作用是緩存數據,解決高速控制器與慢速外設之間的不同步問題,以及解決驅動和I/O口的輸入輸出問題。 類型 存器有多種類型,包括RS存器、D存器、JK
    的頭像 發表于 07-23 11:29 ?713次閱讀