MySQL之事務和redo日誌

来源:https://www.cnblogs.com/duizhangz/archive/2022/05/29/16324299.html
-Advertisement-
Play Games

事務 事務的四個ACID特性。 Atomicity 原子性 Consistency 一致性 Isolation 隔離性 Durability 持久性 原子性 原子性即這個事務的任務要麼全做了,要麼全部沒做,不能出現做一半這種情況。 一致性 一致性即資料庫中的數據必須滿足數據滿足資料庫的約束。 隔離性 ...


事務

事務的四個ACID特性。

Atomicity 原子性

Consistency 一致性

Isolation 隔離性

Durability 持久性

原子性

原子性即這個事務的任務要麼全做了,要麼全部沒做,不能出現做一半這種情況。

一致性

一致性即資料庫中的數據必須滿足數據滿足資料庫的約束。

隔離性

即事務與事務之間相互不打擾,比如兩個事務在實際過程中並不是原子的,兩個事務中的語句是交替運行的,但是隔離性就是要保證兩個事務之間狀態轉換不會互相影響。

持久性

就是一旦事務結束,就要將其保存到磁碟中防止丟失。

事務的狀態

活躍的active:即事務正在運行其中的SQL語句。

部分提交的partially commited:事務執行完成,但是其結果還在記憶體中保存著,沒有刷新到磁碟中。

提交的 commited : 結果成功刷新到磁碟,就從上面部分提交進入該狀態。

失敗的 failed : 就是事務執行過程出現資料庫或操作系統自身的錯誤,就導致了事務提交失敗。

中止 aborted : 就是事務提交失敗,需要將已經修改的語句回滾到事務未執行以前。

image

事務開啟和關閉

begin; 算打開一個事務
....
commit; 提交事務
或者
rollback; 回滾事務

begin算一種打開方式,但是它不能指定事務的打開的類型,只讀、讀寫等

還有一種開始事務方式

start transaction; # 不加參數,預設讀寫事務
start transaction read only; # 只讀事務
start transaction read write; # 讀寫事務
start transaction read only, with consistent shapshot; # 開啟只讀事務和一致性讀。
....
commit; 提交事務
或者
rollback; 回滾事務

關閉就是上面兩個commit 和 rollback 兩種,一個是提交,一個是回滾。

還有就是自動提交。

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set, 1 warning (0.04 sec)

我們的自動提交是預設打開的,自動提交就是我們在沒有指定start transaction 或 begin時,MySQL會為每個語句啟動一個事務,每一條語句相當與都是開了一個事務然後語句結束會自動幫我們提交。

隱式提交

當我們使用begin 或 start transaction ,或則我們關閉了自動提交。事務此時就不會提交,直到我們使用commit或則rollback。但是當出現以下情況,MySQL會幫我們偷偷提交事務。

  • 定義或修改資料庫對象即DDL語句。
  • 隱式使用或修改mysql資料庫中的表
  • 當我們沒提交一個事務時又begin 或 start transaction 就會繼續幫我們自動提交前面已執行的。
  • 載入數據的語句。load data
  • 關於MySQL複製的語句
  • 等等....

保存點savepoint

即我們可以使用savepoint回滾到某個保存點中,但是提交保存點以前的語句,回滾保存點以後的語句。

begin;
...sql語句
savepoint s1;
...SQL語句
rollback to s1; # 此時就會提交s1前的SQL,而回滾s1以後的SQL

redo日誌

如果我們對頁面進行修改的話,我們會先將修改的頁面保存在記憶體的buffer pool中,但是如果出現斷電的情況,我們做的修改就會全部丟失了不是嗎。

我們對事務的持久性進行保證,就是對一個提交的事務做的頁面修改刷新到磁碟中,最簡單粗暴的辦法就是事務提交後直接將記錄刷到磁碟中。

  • 但是刷新到磁碟是十分慢的,而且如果我們只對頁面進行一些很微小的修改,我們都需要以頁為單位和磁碟進行交互,是一個十分不值當的行為。
  • 需要不斷進行隨機IO,因為頁面在磁碟上可能零零散散,我們需要不斷進行隨機IO,效率也是十分低下的。

redo日誌的目的:就是我們對於提交事務的修改進行永久的保存,即使系統崩潰,我們重啟後也能將修改恢復到原樣。

簡單的redo日誌

簡單的redo日誌分為很多中類型,MLOG_1BYTE類型,MLOG_2BYTE類型,MLOG_4BYTE類型,MLOG_8BYTE類型,MLOG_WRITE_STRING類型。

就是如果我們修改只有1,2,4,8,或則連續的一小段個位元組,就會使用這種簡單的日誌進行保存。比如我們對某個系統變數的修改。

image

image

有了簡單的redo日誌,我們可以根據表空間ID和頁號以及偏移量,我們就可以在重啟時找到這個頁,將對應偏移量的數據替換上去就可以了。

複雜的redo日誌

我們平時插入一條數據,可能修改了一個頁面的多個地方,比如頁滿了進行了頁分裂,那修改的地方可就大了去了,以及插入數據也對頁頭一些頁的基本信息又影響。反正就是一個頁的插入可能影響到很多頁。

我們如果對於一個頁面有多處修改,我們使用簡單的redo日誌,一個地方一個地方的寫日誌,那要生成好多的redo日誌,在空間上可能比我們一整個頁面進行刷新效率都低。所以出現了更複雜的redo日誌。

複雜的頁面有以下類型。

PS:緊湊行格式就是Compact、Dynamic行格式,最原始的redundant行格式就是非緊湊的

  • MLOG_REC_INSERT : 創建一個插入的非緊湊行格式頁面的記錄的redo日誌。
  • MLOG_COMP_REC_INSERT:創建一個插入的緊湊行格式頁面的記錄的redo日誌。
  • MLOG_COMP_PAGE_CREATE:創建一個存儲緊湊行格式的頁面的redo日誌。
  • MLOG_COMP_REC_DELETE:創建一個刪除的一個緊湊行格式頁面的記錄的redo日誌。
  • MLOG_COMP_LIST_START_DELETE:表示從某條記錄給定記錄開始刪除頁面中一系列使用緊湊行格式頁面的記錄的redo日誌。
  • MLOG_COMP_LIST_END_DELETE:表示刪除停止的記錄的redo日誌和MLOG_COMP_LIST_START_DELETE是一套的。
  • ....還有很多

我們要理解這個複雜頁面,就要把簡單redo頁面的想法拋棄掉。這個複雜redo頁面並不是存儲某個偏移量修改的新值,我把它理解為它存儲的是這個操作,就是我們插入一條數據,這個redo就是把這個操作存儲起來了。但是它實際上並不是這樣的哈。

這些redo日誌可以從物理和邏輯層面看。

  • 物理層面上看,這些日誌指明瞭對哪個表空間的那個頁進行修改了。
  • 邏輯層面上看,在系統崩潰重啟時,並不能直接載入這些類型的redo日誌。而是需要進行調用函數進行對這些redo日誌處理,然後才能恢復要原樣。

上面寫得很清楚了需要調用函數,說明這些redo只是存儲一些基礎數據,然後調用函數後才能根據這些基礎數據對頁面進行恢復。而並不是像簡單redo頁面那樣直接存儲頁面的數據哦。

看了好幾遍懵逼,就是一直認為它存儲的就是修改頁面的數據,其實不然,它存儲的是進行該操作後用來複原的基本數據。

歸根結底,說了redo的不同頁面類型只不過就是我們需要redo頁面然後將資料庫恢復要出錯前的模樣。

Mini-Transaction

以組的形式寫入redo日誌

我們在寫入redo日誌的時候,我們會考慮到一個情況就是我們的操作是原子的,比如說我們插入一條記錄,我們不僅僅要更改頁的數據,還要更改頁頭的基本信息,有時候還要更新父索引節點的數據。這一系列操作,都是密不可分的,如果一個沒有恢復,那生成的數據將會是錯誤的。所以MySQL將會以組的形式寫入redo日誌。

MySQL將redo日誌分為組的形式,對於需要保證原子性的一系列操作,就會在redo日誌後面加上一個特殊類型的redo日誌。代表一條完整的redo日誌。

image

但是也會出現需要保證原子性操作的redo日誌只有一條redo日誌。因為MySQL要保證儘量節省空間嘛。所以會在類型的最高位設置代表是否是一條單一的redo日誌。

image

Mini-Transaction

MySQL將對頁面中的一次原子操作過程稱之為Mini-Transaction,簡稱mtr。一個mtr就代表一組redo日誌。我們接下來的redo的介紹很多都會以mtr為一個單位。

image

redo日誌的寫入

MySQL以mtr的形式來存儲每一組日誌,但是我們redo日誌是怎麼個順序寫入磁碟的呢?當然呢,和磁碟打交道就是意味著慢,所以redo日誌首先還是會寫入記憶體的緩衝區中然後在慢慢地寫入磁碟哈。我們先將寫入記憶體的過程。

MySQL設計了一個redo log block的數據結構來存儲mtr,大小為512位元組。

  • header 頭部呢就存儲一些基本信息
    • HDR_NO 唯一標號,省略前面的英文單詞
    • HDR_DATA_LEN 已使用的數據長,初始為12,寫滿就是512.
    • FIRST_REC_GROUP 該block中第一個mtr中第一條redo日誌的偏移量
    • CHECKPOINT_NO 就是checkpoint的序號
  • body 就是存儲mtr的地方
  • trailer 就是尾部放檢查和。驗證完整性的。

image

然後我們有了這個數據結構,就可以引出log buffer 簡言之就是redo日誌緩衝區,用來緩存redo日誌的,在MySQL伺服器啟動時會像操作系統申請的一段連續的記憶體空間,和buffer pool差不多。

我們通過innodb_log_buffer_size可以查看redo日誌緩衝區的大小,預設為16M。

mysql> show variables like 'innodb_log_buffer_size';
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set, 1 warning (0.00 sec)

image

結構如上圖,我們以mtr為單位將redo日誌寫入log buffer。

但是我們應該在哪裡插入呢?所以log buffer維護了一個叫做buf_free的全局變數,用來指向空閑的值。然後我們獲取buf_free就可以直接在那個位置插入。

image

我們還有一個問題就是在log block header 中有個屬性, log_block_first_rec_group 這個屬性有什麼用呢?

image

如上圖,我們插入了4個mtr分別屬於兩個事務,我們用來記錄這個log_block_first_rec_group的這個屬性呢記錄了這個block中第一個mtr的第一個redo頁面的偏移量。

就像上面的mtr_t1_2一樣,一下占了三個block,在第二個頁面中log_block_first_rec_group的記錄是512,就說明瞭當前的block是延續之前的mtr。同一第三個頁面我們就可以知道新的mtr在哪裡。

所以呢這個log_block_first_rec_group屬性值的作用是讓我們知道當前block有沒有接續之前block的部分,如果有才可以知道,不然我們無法識別這是一個新的mtr還是接續的mtr。

redo日誌刷盤

redo日誌從redo log buffer中存儲進入磁碟中是講究時機的,同時呢由於存儲到磁碟是很慢的,所以需要緩衝區的存在,讓線程阻塞在那裡等跟磁碟IO的資源那也是不理智的對不對。

以下是redo刷盤的時機

  • log buffer空間不足時。
  • 事務提交時(要保證事務的持久性就得把redo刷到磁碟中)
  • 後臺線程不斷刷盤,大概每秒刷一次。
  • 正常關閉伺服器
  • 做checkpoint時
  • 其他等情況。。。

redo日誌文件

我們可以從根目錄下的data文件夾中查看到兩個文件,預設是兩個。

image

我們可以修改系統變數,在啟動時修改log文件數量

mysql> show variables like 'innodb_log_files_in_group';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2     |
+---------------------------+-------+
1 row in set, 1 warning (0.00 sec)

在啟動時指定log文件的大小一次來修改,預設48M。

mysql> show variables like 'innodb_log_file_size';
+----------------------+----------+
| Variable_name        | Value    |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
1 row in set, 1 warning (0.00 sec)

image

我們將redo日誌寫入磁碟中,本質上就是把block從記憶體中複製了一份到磁碟的ib_logfile文件中。

ib_logfile是由512位元組的block組成的,ib_logfile的前2048位元組即4個block用來存儲一些基本的管理信息。後面剩餘的就是用來存儲從記憶體中讀取來的block,每個block同樣也是512位元組。

image

首先介紹前4個block塊主要是存儲哪些管理信息。

image

  • log file header 的組成

image

  • checkpoint1組成

image

  • 第三個沒用,第四個和checkpoint1一樣。

Log Sequeue Number(LSN)

我們一直在前面提到的LSN值,所以它代表著什麼呢?我們可以叫日誌序列號,LSN的初始值預設為8704。

我們前面提到的log buffer作為redo日誌的緩衝區,有兩個指針我們可以回想一下,buf_free和buf_next_to_write兩個全局變數,一個代表當前緩衝區空閑的地方,一個代表下一個要log buffer寫入磁碟的mtr地址。我們可以知道那些mtr還沒寫入磁碟中。

在buffer pool中維護著一個lsn值,當系統初始化沒有mtr插入時,就是8716 即8704 + 12 的block header。隨著mtr的插入到block中,會不斷增大。

每個mtr都有一個對應的lsn值,lsn值越小代表redo日誌產生得越早。它其實就和buf_free 差不多,只不過它是代表著一個序列號。

image

flushed_to_disk_lsn

innodb也在buffer pool中維護了一個全局變數叫做flushed_to_disk_lsn,和這個buf_next_to_write有著異曲同工之處。它是用來維護buffer pool中已經刷新到磁碟的lsn。

當我們沒有將緩衝區中的mtr刷新到磁碟中,lsn就不會發生改變,當我們將mtr刷到磁碟的redo日誌文件中時,lsn就會增加相應的偏移量 (不是很懂,上面講我們是以block的形式向磁碟刷新redo頁面的)。當然如果我們又跨過了頁首或者頁尾,我們就還需要添加4位元組的頁尾長度。

思路好亂,感覺書上沒講清楚或者是我沒有get到作者的點吧。

flushed_to_disk_lsn直接點說就是一個從8706開始的數字,跟著刷新到磁碟的大小增大而增大。

flush鏈表中的LSN

我們之前簡單提到過的flush的結構,在控制塊中會存放兩個關於頁面修改的LSN。

  • oldest_modification : 如果該頁面被修改,這裡將保存頁面的第一次修改時mtr開始時的LSN值。可以理解為mtr插入到buffer pool前的lsn值。
  • newest_modification : 如果對該頁面進行修改,將保存mtr插入結束後的lsn值。對於每一次修改,這個值都會改變。

我們知道flush鏈表是根據第一次修改的時間從大到小排序的,最新插入的會被排在鏈表首部。其實就是按照oldest_modification 的值進行從大到小排序的,最早進行修改,向log buffer 寫入mtr的頁面的LSN。

我們在這裡需要知道的是我們oldest_modification 保存的是頁面第一次修改的時候向buffer pool插入mtr前buffer pool中維護的LSN值是多少,newest_modification 就是最近一次修改時buffer pool在插入mtr後buffer pool的值是多少。

image

像上面我們在mtr1中修改了a頁面,在mtr2中修改了b,c頁面。他們的LSN值就是上面的所示。我們可以算一些8716就是8704 + 12 就是第一個插入的mtr之前的LSN初始的大小嘛。8916-8716 = 200就是mtr1的大小嘛。

但是我們需要註意的是,重覆修改的頁面不會重新進行插入控制塊嘛,前面文章好像說過,就是我們怎麼找鏈表中有沒有對應頁面的控制塊呢?就是通過哈希表找到key為是表空間+頁號組成的鍵,然後我們修改其newest_modification 的值就好了。

redo日誌文件的LSN

我們提到了在redo日誌文件中log file header 保存了一個redo文件開始的LSN,LSN就是在文件基本信息2048位元組的位置LSN值為8704開始計算。

image

checkpoint

redo日誌對於系統崩潰恢復來說是十分重要的存在,但是如果系統不崩潰的話,這樣的操作是沒有意義的,且耗費性能的。但是當系統崩潰重啟的時候innodb是怎麼知道哪些redo日誌是已經刷新到磁碟了,還是沒有呢?

我們將上述的mtr_1刷新到磁碟了,這是在日誌文件中我們就可以將mtr1的記錄覆蓋掉,我們會將日誌文件中頭部的4個block中存儲checkpoint進行+1的操作,並修改其存儲的LSN。可以回過頭查看redo日誌文件的組成。以上這個操作就叫做伺服器做了一次checkpoint。

具體步驟如下:

  1. 首先我們去flush鏈表中找到最後一個控制塊,找到它的oldest_modification ,它的值就代表當前已經刷新的LSN的值。為什麼呢?仔細想想,它代表著這個mtr插入前的LSN值,它又是最後一個控制塊,代表著這是還沒刷新到磁碟的最早的臟頁 (刷新到磁碟就不會在flush鏈表裡了)。說明這個oldest_modification 代表著還沒刷新mtr的LSN。
  2. 將這個oldest_modification 的值賦值給checkpoint_LSN。
  3. 將日誌文件頭部中的checkpoint中維護的基本信息進行更新,包括編號、偏移量、LSN。

以上的checkpoint的信息只會保存到第一個redo日誌文件的管理信息中去。

還有一點就是checkpoint有1和2,對於他們來說,就是LSN是偶數的時候就保存到2,奇數就保存到1。

innodb中的LSN值

mysql> show engine innodb status;
LOG
---
Log sequence number          118084165
Log buffer assigned up to    118084165
Log buffer completed up to   118084165
Log written up to            118084165
Log flushed up to            118084165
Added dirty pages up to      118084165
Pages flushed up to          118084165
Last checkpoint at           118084165
16 log i/o's done, 0.00 log i/o's/second

對於事務一致性的控制

我們在事務中提到過的持久性,如果我們要保證事務的持久性,就得在事務結束的時候將該事務產生的mtr刷新到磁碟上,但是在事務結束的時候立刻刷新到磁碟上是十分耗時的。

但是呢如果我們不及時刷新,選擇將其先放到緩衝區裡面,但是出現系統崩潰,事務的操作就沒有辦法恢復了,無法保證其一致性。

在性能和一致性上我們可以進行選擇。對innodb_flush_log_at_trx_commit系統變數進行設置

mysql> show variables like 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
1 row in set, 1 warning (0.00 sec)
  • 0代表事務提交不會立刻將mtr刷新到磁碟,而是讓後臺線程自己去慢慢刷。
  • 1即預設值,代表事務提交時必須把mtr刷新到磁碟中。
  • 2代表事務提交必須將mtr刷到操作系統的緩衝區。

innodb_flush_log_at_trx_commit值為2,我們進行刷新磁碟,從資料庫的緩衝區中下來調用操作系統的執行對磁碟進行操作,還會先進入操作系統的緩衝區中讓操作系統去操作,如果操作系統沒崩必然也可以保證事務的一致性,但是如果操作系統也崩了,那就不能保證了。我們值為1是代表必須刷新到磁碟中,即操作系統將數據真正刷到磁碟上了。

崩潰恢復

確定恢復的起點

對於已經刷新到磁碟的mtr來說,沒有必要進行再次恢復,所以我們需要對於起點進行確認。

我們從checkpoint1和checkpoint2拿出LSN,因為倆個地方都存了checkpoint的LSN,所以比較哪個最大,就可以確定需要恢復redo的起點。

確定恢復的終點

對於每個block來說,都維護這一個len,我們只要讀到len小於512的,就可以知道這一頁是沒有滿的,然後根據其具體長度,就可以知道恢復的終點。

怎麼恢復

我們就是從起點,慢慢掃描每一個redo日誌,對其進行複原,直到終點。

加速方法:

  1. 使用哈希表

    就是將每個頁面的redo日誌,放入哈希表中,根據spaceID和page Number來確定哈希表的散列值,然後根據插入的先後排序,先插入在前。然後我們就可以根據一個頁面一個頁面進行更新,這樣避免了隨機IO。

  2. 跳過已經刷新的頁面

    我們在做了一次checkpoint後,又有頁面從LRU鏈表或者flush鏈表中的頁面更新到磁碟中。因為checkpoint不是一直在做的。

    我們怎麼知道呢?在每個頁面的File Header中有一個FIL_PAGE_LSN的屬性,該屬性記錄了最近一次刷新頁面的newest_modification 值。如果當前LSN小於這個FIL_PAGE_LSN的值,代表已經刷新到後面的記錄了,不需要更新了,直接跳過。


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

-Advertisement-
Play Games
更多相關文章
  • 電腦、平板,只要有瀏覽器就能寫代碼,頁面效果接近桌面版vscode,編譯運行代碼都在免費的微軟伺服器上,心動嗎?隨本文一起行動吧 ...
  • 項目簡介 novel 是一套基於時下最新 Java 技術棧 Spring Boot 3 + Vue 3 開發的前後端分離的學習型小說項目,配備詳細的項目教程手把手教你從零開始開發上線一個生產級別的 Java 系統,由小說門戶系統、作家後臺管理系統、平臺後臺管理系統等多個子系統構成。包括小說推薦、作品 ...
  • 當你需要為你的單元測試想出有用的測試數據時,你是否也經常沒有靈感?不要擔心,Java Faker來救你了!在這篇博客中,你將學習如何生成你的測試數據。在這篇博客中,你將學習如何生成你的測試數據。 1. 簡介 編寫測試數據是編寫測試時最難的任務之一。通常你會在使用數字的時候看到123,或者在需要名字的 ...
  • 閱讀導航 前言 案例一 案例二 案例三(本文介紹的方式) 如何使用? 控制項如何開發的? 總結 1. 前言 案例一 站長分享過 眾尋 大佬的一篇 WPF 簡易新手引導 一文,新手引導的效果挺不錯的,如下圖: 該文給出的代碼未使用 MVVM 的開發方式,提示框使用的用戶控制項、蒙版窗體樣式與後臺代碼未分離 ...
  • 1.什麼是ScheduleMaster ScheduleMaster是分散式任務調度系統。簡稱:集中任務調度系統,最簡單的理解ScheduleMaster,就是對不同的系統裡面的調度任務做統一管理的框架。 例如我們現在有多個系統,每個系統針對自己處理不同的業務場景。衍生出自己的調度任務,想象一下,如 ...
  • C#-WinForm窗體仿Android桌面(左右翻頁) 利用ApeForms擴展方法使控制項平滑運動,並以此實現一個仿Android桌面翻頁的效果。 ...
  • autofac需要下載Autofac+Autofac.Extensions.DependencyInjection 推薦創建一個類 我這裡TestServer是介面和實現類都在這個裡面,直接讀取進行批量註入 然後去Program進行替換 builder.Host.UseServiceProvider ...
  • 到nuget里下載log4net 這裡為幫組類 可以改為靜態方法 private static ILog logger; static LogImp()//這個是構造函數 { if (logger == null) { var repository = LogManager.CreateReposi ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...