日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 提交事务_MySQL事务提交过程

發布時間:2024/3/12 数据库 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 提交事务_MySQL事务提交过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、MySQL事務提交過程(一)

MySQL作為一種關系型數據庫,已被廣泛應用到互聯網中的諸多項目中。今天我們來討論下事務的提交過程。

由于mysql插件式存儲架構,導致開啟binlog后,事務提交實質是二階段提交,通過兩階段提交,來保證存儲引擎和二進制日志的一致。

此目錄節點只討論binlog未打卡狀態下的提交流程,后續會討論打開binlog選項后的提交邏輯。

測試環境

OS:WIN7

ENGINE:

bin-log:off

DB:

測試條件

set autocommit=0;

------------------------------

--Table structure for `user`

------------------------------

DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (

`id`int(20) NOT NULL,

`account`varchar(20) NOT NULL,

`name`varchar(20) NOT NULL,PRIMARY KEY(`id`),KEY`id` (`id`) USING BTREE,KEY`name` (`name`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

測試語句

insert into user values(1, 'sanzhang', '張三');

commit;

一般常用的DML:Data Manipulation Language 數據操縱語言,對表的數據進行操作,(insert、update、delete )語句

和?DCL:Data Control Language 數據庫控制語言(創建用戶、刪除用戶、授權、取消授權)語句

和 DDL:Data Definition Language 數據庫定義語言,對數據庫內部的對象進行創建、刪除、修改的操語句,

均是使用MySQL提供的公共接口mysql_execute_command,來執行相應的SQL語句。我們來分析下mysql_execute_command接口執行的流程:

mysql_execute_command

{

switch (command)

{caseSQLCOM_INSERT:

mysql_insert();break;caseSQLCOM_UPDATE:

mysql_update();break;caseSQLCOM_DELETE:

mysql_delete();break;

......

}if thd->is_error() //語句執行錯誤

trans_rollback_stmt(thd);elsetrans_commit_stmt(thd);

}

從上述流程中,可以看到執行任何語句,最后都會執行trans_rollback_stmt或者trans_commit_stmt,這兩個分別是語句回滾和語句提交。

語句提交,對于非自動模式下,主要有兩個作用:

1、釋放autoinc鎖,這個鎖主要用來處理多個事務互斥的獲取自增序列。因此,無論最后執行的是語句提交還是語句回滾,該資源都是需要立馬釋放掉的。

2、標識語句在事務中的位置,方便語句級回滾。執行commit后,可以進入commit流程。

現在看下具體的事務提交流程:

mysql_execute_command

trans_commit_stmt

ha_commit_trans(thd, FALSE);

{

TC_LOG_DUMMY:ha_commit_low

ha_commit_low()

innobase_commit

{//獲取innodb層對應的事務結構

trx=check_trx_exists(thd);if(單個語句,且非自動提交)

{//釋放自增列占用的autoinc鎖資源

lock_unlock_table_autoinc(trx);//標識sql語句在事務中的位置,方便語句級回滾

trx_mark_sql_stat_end(trx);

}else事務提交

{

innobase_commit_low()

{

trx_commit_for_mysql();trx_commit(trx);

}//確定事務對應的redo日志是否落盤【根據flush_log_at_trx_commit參數,確定redo日志落盤方式】

trx_commit_complete_for_mysql(trx);

trx_flush_log_if_needed_low(trx->commit_lsn);

log_write_up_to(lsn);

}

}

}

trx_commit

trx_commit_low

{

trx_write_serialisation_history

{

trx_undo_update_cleanup//供purge線程處理,清理回滾頁

}

trx_commit_in_memory

{

lock_trx_release_locks//釋放鎖資源

trx_flush_log_if_needed(lsn)//刷日志

trx_roll_savepoints_free//釋放savepoints

}

}

MySQL是通過WAL方式,來保證數據庫事務的一致性和持久性,即ACID特性中的C(consistent)和D(durability)。

WAL(Write-Ahead Logging)是一種實現事務日志的標準方法,具體而言就是:

1、修改記錄前,一定要先寫日志;

2、事務提交過程中,一定要保證日志先落盤,才能算事務提交完成。

通過WAL方式,在保證事務特性的情況下,可以提高數據庫的性能。

從上述流程可以看出,提交過程中,主要做了4件事情,

1、清理undo段信息,對于innodb存儲引擎的更新操作來說,undo段需要purge,這里的purge主要職能是,真正刪除物理記錄。在執行delete或update操作時,實際舊記錄沒有真正刪除,只是在記錄上打了一個標記,而是在事務提交后,purge線程真正刪除,釋放物理頁空間。因此,提交過程中會將undo信息加入purge列表,供purge線程處理。

2、釋放鎖資源,mysql通過鎖互斥機制保證不同事務不同時操作一條記錄,事務執行后才會真正釋放所有鎖資源,并喚醒等待其鎖資源的其他事務;

3、刷redo日志,前面我們說到,mysql實現事務一致性和持久性的機制。通過redo日志落盤操作,保證了即使修改的數據頁沒有即使更新到磁盤,只要日志是完成了,就能保證數據庫的完整性和一致性;

4、清理保存點列表,每個語句實際都會有一個savepoint(保存點),保存點作用是為了可以回滾到事務的任何一個語句執行前的狀態,由于事務都已經提交了,所以保存點列表可以被清理了。

關于mysql的鎖機制,purge原理,redo日志,undo段等內容,其實都是數據庫的核心內容。

MySQL 本身不提供事務支持,而是開放了存儲引擎接口,由具體的存儲引擎來實現,具體來說支持 MySQL 事務的存儲引擎就是 InnoDB。

存儲引擎實現事務的通用方式是基于 redo log 和 undo log。

簡單來說,redo log 記錄事務修改后的數據, undo log 記錄事務前的原始數據。

所以當一個事務執行時實際發生過程簡化描述如下:

先記錄?undo/redo log,確保日志刷到磁盤上持久存儲。

更新數據記錄,緩存操作并異步刷盤。

提交事務,在?redo log?中寫入?commit?記錄。

在 MySQL 執行事務過程中如果因故障中斷,可以通過 redo log 來重做事務或通過 undo log 來回滾,確保了數據的一致性。

這些都是由事務性存儲引擎來完成的,但 binlog 不在事務存儲引擎范圍內,而是由 MySQL Server 來記錄的。

那么就必須保證 binlog 數據和 redo log 之間的一致性,所以開啟了 binlog 后實際的事務執行就多了一步,如下:

先記錄?undo/redo log,確保日志刷到磁盤上持久存儲。

更新數據記錄,緩存操作并異步刷盤。

將事務日志持久化到?binlog。

提交事務,在?redo log?中寫入commit記錄。

這樣的話,只要 binlog 沒寫成功,整個事務是需要回滾的,而 binlog 寫成功后即使 MySQL Crash 了都可以恢復事務并完成提交。

要做到這點,就需要把 binlog 和事務關聯起來,而只有保證了 binlog 和事務數據的一致性,才能保證主從數據的一致性。

所以 binlog 的寫入過程不得不嵌入到純粹的事務存儲引擎執行過程中,并以內部分布式事務(xa 事務)的方式完成兩階段提交。

二、MySQL事務提交過程(二)

前一章節我們介紹了在關閉binlog的情況下,事務提交的大概流程。之所以關閉binlog,是因為開啟binlog后事務提交流程會變成兩階段提交,這里的兩階段提交并不涉及分布式事務,當然mysql把它稱之為內部xa事務(Distributed Transactions),與之對應的還有一個外部xa事務。

這里所謂的兩階段提交分別是prepare階段和commit階段。

內部xa事務主要是mysql內部為了保證binlog與redo log之間數據的一致性而存在的,這也是由其架構決定的(binlog在mysql層,而redo log 在存儲引擎層);

外部xa事務則是指支持多實例分布式事務,這個才算是真正的分布式事務。

既然是xa事務,必然涉及到兩階段提交,對于內部xa而言,同樣存在著提交的兩個階段。

下文會結合源碼詳細解讀內部xa的兩階段提交過程,以及各種情況下,mysqld crash后,mysql如何恢復來保證事務的一致性。

測試環境在前章節的基礎上加了:

配置文件參數:

log-bin=D:\mysql\log\5-6-21\mysql-bin

binlog_format=ROWset autocommit=0;

innodb_support_xa=1sync_binlog=1;

innodb_flush_log_at_trx_commit=1;

【innodb_flush_log_at_trx_commit=1,sync_binlog=1

不同的模式區別在于,寫文件調用write和落盤fsync調用的頻率不同,所導致的后果是mysqld 或 os crash后,不嚴格的設置可能會丟失事務的更新。

雙一模式是最嚴格的模式,這種設置情況下,單機在任何情況下不會丟失事務更新。】

prepare階段:

1.設置undo state=TRX_UNDO_PREPARED;?//trx_undo_set_state_at_prepare調用

2.刷事務更新產生的redo日志;【步驟1產生的redo日志也會刷入】

MYSQL_BIN_LOG::prepareha_prepare_low

{

engine:

binlog_prepare

innobase_xa_prepare

mysql:

trx_prepare_for_mysql

{1.trx_undo_set_state_at_prepare //設置undo段的標記為TRX_UNDO_PREPARED2.設置事務狀態為TRX_STATE_PREPARED3.trx_flush_log_if_needed //將產生的redolog刷入磁盤

}

}

commit階段:

1.將事務產生的binlog寫入文件,刷入磁盤;

2.設置undo頁的狀態,置為TRX_UNDO_TO_FREE或TRX_UNDO_TO_PURGE;??//?trx_undo_set_state_at_finish調用

3.記錄事務對應的binlog偏移,寫入系統表空間;?//trx_sys_update_mysql_binlog_offset調用

MYSQL_BIN_LOG::commitordered_commit

{1.FLUSH_STAGE

flush_cache_to_file//刷binlog2.SYNC_STAGE

sync_binlog_file//Call fsync() to sync the file to disk.3.COMMIT_STAGE

ha_commit_low

{

binlog_commit

innobase_commit

trx_commit(trx)

{

trx_write_serialisation_history(trx, mtr);//更新binlog位點,設置undo狀態

trx_commit_in_memory(trx, lsn);//釋放鎖資源,清理保存點列表,清理回滾段

}

}

}

在任何情況下(機器掉電)mysqld crash或者os crash,MySQL仍然能保證數據庫的一致性。數據的一致性是如何做到的哪?正是二階段提交。

我們結合幾種場景來分析下二階段提交是如何做到的:

1.prepare階段,redo log落盤前,mysqld crash

2.prepare階段,redo log落盤后,binlog落盤前,mysqld crash

3.commit階段,binlog落盤后,mysqld crash

對于第一種情況,由于redo沒有落盤,毫無疑問,事務的更新肯定沒有寫入磁盤,數據庫的一致性受影響;

對于第二種情況,這時候redo log寫入完成,但binlog還未寫入,事務處于TRX_STATE_PREPARED狀態,這是提交還是回滾呢?

對于第三種情況,此時,redo log和binlog都已經落盤,只是undo狀態沒有更新,雖然redo log和binlog已經一致了,事務是否應該提交?

我們結合mysqld異常重啟后的執行邏輯以及關鍵的源代碼。

對于第三種情況,我們可以搜集到未提交事務的binlog event,所以需要提交;

對于第二種情況,由于binlog未寫入,需要通過執行回滾操作來保證數據庫的一致性。

異常重啟后,如何判斷事務該提交還是回滾

1.讀binlog日志,獲取崩潰時沒有提交的event; ?//info->commit_list中含有該元素

2.若存在,則對應的事務要提交;否則需要回滾。

判斷事務提交或回滾源碼如下:

上面討論了兩階段提交的基本流程,以及服務器異常crash后,mysql如何重啟恢復保證binlog和數據的一致性。

簡而言之,對于異常的xa事務,若binlog已落盤,則事務應該提交;binlog未落盤,則事務就應該回滾。

//異常重啟后,回滾流程

innobase_rollback_by_xid

rollback_by_xid

trx_rollback_resurrected

trx_rollback_active

row_undo

{//從回滾頁獲取undo記錄//分析undo記錄類型if (insert)

row_undo_inselserow_undo_mod

}

//異常重啟后,提交流程

commit_by_xid

trx_commit_for_mysql

//寫binlog接口

handler.cc:binlog_log_row

sql/binlog.cc:commitmysys/my_sync:my_sync

sql/binlog.cc:sync_binlog_file

handler/ha_innodb.cc:innobase_xa_prepare

binlog日志文件是為了解決MySQL主從復制功能而引入的一份新日志文件,它包含了引發數據變更的事件日志集合。

從庫請求主庫發送 binlog 并通過日志事件還原數據寫入從庫,所以從庫的數據來源為 binlog。

這樣 MySQL 主庫只需做到 binlog 與本地數據一致就可以保證主從庫數據一致(暫且忽略網絡傳輸引發的主從不一致)。

本文整理自:

https://www.cnblogs.com/exceptioneye/p/5451960.html

https://www.cnblogs.com/exceptioneye/p/5451976.html

總結

以上是生活随笔為你收集整理的mysql 提交事务_MySQL事务提交过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。