InnoDB鎖初探(一):鎖分類和RR不同場景下的鎖機制

来源:https://www.cnblogs.com/mwss/archive/2023/06/21/17496498.html
-Advertisement-
Play Games

# Mysql資料庫鎖(Innodb) 資料庫鎖是Mysql實現數據一致性的基礎之一,是在事務的基礎之上,基於Mysql Server層或存儲引擎層實現的。 ## 鎖日誌 前置條件: ```sql set GLOBAL innodb_status_output=ON; set GLOBAL inno ...


Mysql資料庫鎖(Innodb)

資料庫鎖是Mysql實現數據一致性的基礎之一,是在事務的基礎之上,基於Mysql Server層或存儲引擎層實現的。

鎖日誌

前置條件:

set GLOBAL innodb_status_output=ON;  

set GLOBAL innodb_status_output_locks=ON;

查看語句:

show engine innodb status\G;

鎖分類

表鎖與行鎖

按照鎖的粒度,可以分為表鎖和行鎖

共用鎖與排他鎖

  • 共用鎖

    1. select *** lock in share mode
    2. Lock Table *** read
    
  • 排他鎖

    1. select  *** for update
    2. Lock Table *** write
    

意向鎖

  1. 意向鎖是表級的

  2. 同樣具有意向共用鎖(IS)、意向排他鎖(IX)

  3. TABLE LOCK table *** trx id *** lock mode IXTABLE LOCK table *** trx id *** lock mode IS

  4. 意向鎖不會與行級鎖衝突,並且意向鎖之間沒有互斥關係

  5. 意向鎖的意義是用於協調表鎖與行鎖之間的互斥關係,確保事務可以正確的請求和釋放鎖。如果沒有意向鎖,當對全表加鎖時,需要遍歷全表,判斷是否存在某些行記錄被加了行鎖,那麼這個加表鎖的操作的性能會差很多。有了意向鎖,A事務對某行記錄加鎖時會先申請意向鎖,申請成功後再加行鎖,加鎖成功後,B事務申請表級鎖時會先判斷表上面的意向鎖是否相容。

  6. 意向共用鎖(IS鎖):事務在請求S鎖之前,先獲取IS鎖

    意向排他鎖(IX鎖):事務在請求X鎖之前,先獲取IX鎖

  7. 相容性:

    意向共用鎖(IS) 意向排他鎖(IX)
    意向共用鎖(IS) 相容 相容
    意向排他鎖(IX) 相容 相容
    意向共用鎖(IS) 意向排他鎖(IX)
    表級共用鎖(S) 相容 互斥
    表級排他鎖(X) 互斥 互斥

記錄鎖(Record Lock)

  1. RECORD LOCKS *** index uniq_idx of table *** trx id *** lock_mode X locks rec but not gapRECORD LOCKS *** index uniq_idx of table *** trx id *** lock_mode S locks rec but not gap
  2. 基於索引創建的,受索引的影響
  3. 同樣具有共用、排他的區別

間隙鎖(Gap Lock)

  1. 間隙鎖是RR模式避免幻讀的基礎
  2. 顧名思義,鎖住的是範圍,比如(-∞,10),(10,15)等開區間
  3. RECORD LOCKS *** index idx_c of table *** trx id *** lock_mode X locks gap before rec

臨鍵鎖(Next-Key Locks)

  1. 記錄鎖、間隙鎖的組合就是臨鍵鎖
  2. 臨鍵鎖是申請鎖時,預設先申請的鎖類型,如果申請失敗,則進行降級,將為間隙鎖或記錄鎖
  3. 不僅鎖住記錄,還會鎖住間隙,比如(-∞,10],(10,15]等區間,前開後閉區間
  4. RECORD LOCKS *** index idx_c of table *** trx id *** lock_mode X

插入意向鎖(Insert Intention Locks)

  1. RECORD LOCKS *** index PRIMARY of table *** trx id *** lock_mode X insert intention waiting

  2. 插入意向鎖可以理解為特殊的Gap鎖的一種,用來提高併發寫的性能。當遇到主鍵或唯一鍵衝突時,會退化為讀鎖

  3. 插入意向鎖和插入意向鎖之間不會互斥(只要記錄本身唯一鍵、主鍵不衝突)。

    示例:

    事務A插入數據27時,獲取到的是(25,30)的間隙鎖和27的行鎖,事務B插入數據28時,獲取到的也是(25,30)的間隙鎖和28的行鎖。

    因為行鎖27和行鎖28不是同一行,所以不會衝突,然後兩個事務獲取到的插入意向鎖不會互相排斥,所以可以插入成功。

自增鎖(AUTO-INC Locks)

  1. TABLE LOCK table *** trx id *** lock mode AUTO-INC waiting
  2. 自增鎖處於表級別的鎖

元數據鎖(metadata lock)

  1. Server層實現的鎖,與引擎層無關

  2. 執行select時,如果有ddl語句,那麼ddl會被阻塞(非online ddl),因為select語句有metadata lock,防止元數據被改掉。

    非online ddl的問題:

    select操作會先獲取 元數據共用鎖(shared MDL),而DDL 操作會先獲取元數據排他鎖(exclusive MDL), 而且不僅僅是先select後ddl 導致ddl阻塞,

    而且ddl後面的select也會被阻塞,因為ddl申請元數據排他鎖的優先順序要比select操作的優先順序要高,只有ddl操作完成後,後面的select才會順利獲取元數據共用鎖,才能繼續執行,因此ddl操作的花費是昂貴的,因此才出現online DDL;

鎖解讀

RR下的有二級索引的情況

CREATE TABLE `a` (
  `a` int(11) NOT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  `aaa` bigint(20) DEFAULT '0',
  PRIMARY KEY (`a`),
  UNIQUE KEY `idx_b` (`b`),
  KEY `idx_c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

image-20230621114912947

select * from a WHERE c = 7 for UPDATE;
MySQL thread id 10, OS thread handle 139897622177536, query id 377 172.18.0.1 wss

對a表添加意向排他鎖
TABLE LOCK table `demo`.`a` trx id 480393 lock mode IX

對a表的idx_c二級索引加臨鍵鎖
RECORD LOCKS space id 97 page no 5 n bits 72 index idx_c of table `demo`.`a` trx id 480393 lock_mode X
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
二級索引idx_c的7加鎖
 0: len 4; hex 80000007; asc     ;;
主鍵索引上的3也會被加鎖
 1: len 4; hex 80000003; asc     ;;

對主鍵索引加記錄鎖,對3進行加鎖
RECORD LOCKS space id 97 page no 3 n bits 72 index PRIMARY of table `demo`.`a` trx id 480393 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
第一個欄位是主鍵,被加鎖
 0: len 4; hex 80000003; asc     ;;
最近一次被更新的事務id
 1: len 6; hex 000000009c29; asc      );;
回滾指針
 2: len 7; hex be00000147011c; asc     G  ;;
該行第2、3、4、5個欄位
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;
 6: len 8; hex 8000000000000000; asc         ;;

對idx_c索引樹上加間隙鎖
RECORD LOCKS space id 97 page no 5 n bits 72 index idx_c of table `demo`.`a` trx id 480393 lock_mode X locks gap before rec
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
二級索引idx_c上對9加鎖
0: len 4; hex 80000009; asc     ;;
主鍵索引上的5也會被鎖住
 1: len 4; hex 80000005; asc     ;;

RR下的無二級索引的情況

CREATE TABLE `tm` (
  `i` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

image-20230621140418689

SELECT * FROM tm WHERE i = 1 FOR UPDATE;
MySQL thread id 25, OS thread handle 139897622718208, query id 556 172.18.0.1 wss

對tm表添加意向排他鎖
TABLE LOCK table `demo`.`tm` trx id 480412 lock mode IX

由於表定義沒有顯示的索引,而InnoDB又是索引組織表,會自動創建一個索引,這裡面叫index GEN_CLUST_INDEX  
由於沒有索引,那麼會對每條記錄都加上臨鍵鎖
RECORD LOCKS space id 110 page no 3 n bits 80 index GEN_CLUST_INDEX of table `demo`.`tm` trx id 480412 lock_mode X
supremum 指的是頁裡面的最後一條記錄(偽記錄,通過select查不到,並不是真實記錄);還有Infimum表示頁面中的第一個記錄(偽記錄)
通過supremum 鎖住index GEN_CLUST_INDEX的最大值到正無窮大的區間,這樣就可以鎖住全部記錄,以及全部間隙,相當於表鎖
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000300; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea000001960110; asc        ;;
 3: len 4; hex 80000001; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000301; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea00000196011e; asc        ;;
 3: len 4; hex 80000002; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000302; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea00000196012c; asc       ,;;
 3: len 4; hex 80000003; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000303; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea00000196013a; asc       :;;
 3: len 4; hex 80000004; asc     ;;

Record lock, heap no 6 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000304; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea000001960148; asc       H;;
 3: len 4; hex 80000005; asc     ;;

Record lock, heap no 7 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000305; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea000001960156; asc       V;;
 3: len 4; hex 80000005; asc     ;;

Record lock, heap no 8 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000306; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea000001960164; asc       d;;
 3: len 4; hex 80000005; asc     ;;

Record lock, heap no 9 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000307; asc       ;;
 1: len 6; hex 00000007548e; asc     T ;;
 2: len 7; hex ea000001960172; asc       r;;
 3: len 4; hex 80000005; asc     ;;

鎖演算法

自增鎖

​ 自增列的維護與數據的新增有關,任何產生新數據的語句都可以稱為”Insert like“,大致分3種,分別是simple insert、bulk inserts、mixed-mode inserts

simple insert:插入記錄的行數時確定的,比如:insert into valuesreplace

bulk inserts:插入的記錄行數不能馬上確定的,比如:insert ... select ...replace ... selectload data

mixed-mode inserts:部分自增列的值給定或者不給定,比如INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');INSERT ... ON DUPLICATE KEY UPDATE

死鎖

自增鎖死鎖常常出現在數據遷移過程中。常見的數據遷移大多以雙寫來實現,類似一個進程負責從舊表往新表寫(insert ... select ...),而應用程式則繼續往新表寫,此時新表可能會發生死鎖。

鎖模式

  • innodb_autoinc_lock_mode = 0 (“traditional” lock mode)

    任何一種insert-like語句,都會產生一個表級的自增鎖,性能差,但是足夠安全

  • innodb_autoinc_lock_mode = 1 (“consecutive” lock mode)

​ 這是預設的鎖模式,當發生bulk inserts時,會產生一個表級的自增鎖直到語句執行結束,註意不是事務結束。對於simple insert,則使用輕量鎖,只要獲取相應的auto increment就釋放鎖,不會等待語句結束。當表被加上自增鎖後,這種輕量鎖不會加鎖成功,會等待。

​ 優點是性能較好,缺點還是會產生表級的自增鎖,因為要保證自增id的連續性,防止bulk inserts時,被其他insert 語句搶走 auto increment值。

  • innodb_autoinc_lock_mode = 2 (“interleaved” lock mode)

​ 當進行bulk insert 時,不會產生表級別的自增鎖,因為他是允許其他insert 插入的,新增一條記錄,插入分配一個auto increment值,不會預分配。

​ 優點是性能較好,缺點是一次bulk inserts 產生的自增列並不是連續的,同時SBR模式下的主從複製可能會產生數據不一致錯誤,該錯誤可以通過將主從複製改為RBR模式。

​ PS:SBR模式的主從複製:binlog格式以statement的日誌格式;RBR模式的主從複製:binlog格式以基於行(Row)的日誌格式(推薦)。

優化

如果binlog-format是row模式的,而且不關心一條bulk insert的自增列的值連續且提交順序與自增列值大小的順序一致,那麼可以設置innodb_autoinc_lock_mode = 2 來提高性能

一條bulk insert 自增列是否連續有時候會影響分頁查詢,有時候為瞭解決深分頁查詢問題,會採用每次分頁查詢的最大值來進行分頁,比如

select * from xx where id>1 limit N
select * from xx where id>1+N limit N
select * from xx where id>1+N+N limit N

當id=101的記錄先提交,該記錄的值剛好是當前頁的最大值,此時id=100數據被提交,那麼下次分頁查詢會從101開始查詢,就會造成這次翻頁的數據存在缺失的情況。如果分頁查詢中包含oder by id的查詢或者有and create_time < (now() - INTERVAL 5 second),那麼可以通過往前翻頁來找到,但是歸根結底當前分頁的數據需要等待100數據被提交後刷新分頁來解決。

通用鎖

  • 鎖是在索引上實現的

  • 假設有一個key,有5條記錄, 1,3,5,7,9. 如果where id<5 , 那麼鎖住的區間不是(-∞,5),而是(-∞,1],(1,3],(3,5] 多個區間組合而成;如果where id =5,那麼鎖住的區間是(3,5],(5,9]

  • next-key lock 降級為 record lock的情況:

    如果是唯一索引,且查詢條件得到的結果集是1條記錄(等值,而不是範圍),那麼會降級為記錄鎖

    典型的案例:where primary_key = 1 (會降級), 而不是 where primary_key < 10 (由於返回的結果集不僅僅一條,那麼不會降級)

  • 上鎖,不僅僅對輔助索引加鎖,還需要對主鍵索引加鎖;不僅僅對主鍵索引加鎖,還需要對輔助索引加鎖

RR下的Update鎖機制

如果

  1. select * from xx where col <比較運算符> M for update
  2. M->next-rec: 表示M的下一條記錄
  3. M->pre-rec: 表示M的前一條記錄
第一輪總結
  • 等值查詢M,非唯一索引的加鎖邏輯

​ (M->pre-rec,M],(M,M->next-rec]

  • 等值查詢M,唯一鍵的加鎖邏輯

​ [M], next-lock 降級為 record locks

  • >= ,非唯一索引的加鎖邏輯

​ (M->pre_rec,M],(M,M->next-rec]....(∞]

  • >= ,唯一索引的加鎖邏輯
    (M->pre_rec,M],(M,M->next-rec]....(∞]

  • <= , 非唯一索引的加鎖邏輯
    (-∞] ... (M,M->next-rec]

  • <= , 唯一索引的加鎖邏輯
    (-∞] ... (M,M->next-rec]

  • >, 非唯一索引的加鎖邏輯
    (M,M->next-rec] ... (∞]

  • >, 唯一索引的加鎖邏輯
    (M,M->next-rec] ... (∞]

  • < , 非唯一索引的加鎖邏輯
    (-∞] ... (M->pre_rec,M]

  • < , 唯一索引的加鎖邏輯
    (-∞] ... (M->pre_rec,M]

第二輪總結合併
  • 等值查詢M,非唯一索引的加鎖邏輯
    (M->pre-rec,M],(M,M->next-rec]
  • 等值查詢M,唯一鍵的加鎖邏輯
    [M], next-lock 降級為 record locks
    這裡大家還記得之前講過的通用演算法嗎:
    next-key lock 降級為 record lock的情況:
    如果是唯一索引,且查詢條件得到的結果集是1條記錄(等值,而不是範圍),那麼會降級為記錄鎖
  • >= ,加鎖邏輯
    (M->pre_rec,M],(M,M->next-rec]....(∞]
  • >, 加鎖邏輯
    (M,M->next-rec] ... (∞]
  • <= , 加鎖邏輯
    (-∞] ... (M,M->next-rec]
  • < , 加鎖邏輯
    (-∞] ... (M->pre_rec,M]
最後的疑問和總結

為什麼要對M->next-rec 或者 M->pre-rec ?

因為為了防止幻讀。

image-20230621145511124

RR下的Insert鎖機制

Insert 的流程(沒有唯一索引的情況): insert N
  1. 找到大於N的第一條記錄M
  2. 如果M上面沒有gap , next-key locking的話,可以插入 , 否則等待 (對其next-rec加insert intension lock,由於有gap鎖,所以等待)
Insert 的流程(有唯一索引的情況): insert N
  1. 找到大於N的第一條記錄M,以及前一條記錄P
  2. 如果M上面沒有gap , next-key locking的話,進入第三步驟 , 否則等待(對其next-rec加insert intension lock,由於有gap鎖,所以等待)
  3. 檢查p:
    判斷p是否等於n:
    如果不等: 則完成插入(結束)
    如果相等:
    再判斷P 是否有鎖,
    如果沒有鎖:
    報1062錯誤(duplicate key) --說明該記錄已經存在,報重覆值錯誤
    加S-lock --說明該記錄被標記為刪除, 事務已經提交,還沒來得及purge
    如果有鎖: 則加S-lock --說明該記錄被標記為刪除,事務還未提交.
  • insert intension lock 有什麼用呢?鎖的相容矩陣是啥?
  1. insert intension lock 是一種特殊的Gap lock,記住非常特殊哦
  2. insert intension lock 和 insert intension lock 是相容的,其次都是不相容的
  3. Gap lock 是為了防止insert, insert intension lock 是為了insert併發更快,兩者是有區別的
  4. 什麼情況下會出發insert intension lock ?
    當insert的記錄M的 next-record 加了Gap lock才會發生,record lock並不會觸發

參考資料

  1. http://keithlan.github.io/2017/06/05/innodb_locks_1/
  2. https://www.hhcycj.com/post/item/441.html
  3. https://baijiahao.baidu.com/s?id=1744632613955812703&wfr=spider&for=pc

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # Python的多線程和多進程 ## 一、簡介 併發是今天電腦編程中的一項重要能力,尤其是在面對需要大量計算或I/O操作的任務時。Python 提供了多種併發的處理方式,本篇文章將深入探討其中的兩種:多線程與多進程,解析其使用場景、優點、缺點,並結合代碼例子深入解讀。 ## 二、多線程 Pyth ...
  • 類型的別名是C#12的一種比較“實用”的“新功能”。它可以讓你在開發過程中使用 using 別名指令創建任何類型的別名,也可以為元組類型、數組類型、指針類型或其他不安全類型創建語義別名,這樣可以通過類型知道當前參數的含義,降低錯誤率。之前的C#版本也支持類型別名,但是使用沒有這麼優雅。C#12的使用 ...
  • 函數 NCalc 本身已經實現的函數列表如下: 函數名描述用例用例結果 Abs 返回絕對值 Abs(-1) 1M Acos 返回餘弦值對應的角度 Acos(1) 0d Asin - - d Atan - - d Ceiling 向上取整 Ceiling(1.5) 2d Cos - - d Exp 相 ...
  • 在日常工作中,我們常常需要將SVG轉換為PDF格式。這是因為SVG格式的圖像在列印時可能會出現問題,例如失去解析度或無法正確適應紙張大小。與此相比,PDF格式則專門用於列印和共用文檔,可以確保高質量輸出,並且能夠自動適應不同的紙張大小。在本文中,我們將介紹如何使用編程方式將SVG文件轉換為PDF,並... ...
  • 產品設計出來之後啊,大家使用的時候覺得反過來使用更加便捷。但是屏幕顯示是反的。那怎麼辦那????? 修改硬體費時費工,那能否軟體實現那????? 如果純軟體使用那就太費系統資源了。於是就想到了使用全志R528 自帶的G2D功能(硬體加速功能)。 使用它進行旋轉,後又發現uboot階段系統沒有G2D導 ...
  • ![image](https://img2023.cnblogs.com/blog/2907560/202306/2907560-20230621111419985-1823538417.png) 本文是筆者 slab 系列的最後一篇文章,為了方便大家快速檢索,先將相關的文章列舉出來: - [《細節 ...
  • 在一套MySQL MGR集群測試環境中,同事測試時,在my.cnf參數文件中修改了autocommit參數(修改為autocommit=0),結果上周五,由於系統管理員要升級RHEL 8.8的系統補丁,所以將這這三台MySQL的資料庫服務關閉了,升級完RHEL 8.8的系統補丁後,啟動MySQL的集 ...
  • 本文從 Commons DBCP testOnBorrow 的作用機制著手,管中窺豹,從一點去分析資料庫連接池獲取的過程以及架構分層設計。以下內容會按照每層的作用,貫穿分析整個調用流程。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...