MySQL(3)事務與存儲引擎

MySQL事務與存儲引擎

3.1-數據庫事務

事務的定義

一系列有序的數據庫操作。

  • 要么全部成功
  • 要么全部回退到操作前的狀態
  • 中間狀態對其他連接不可見

事務的基本操作

基本操作 說明
start transaction 開始事務
commit 提交(全部完成)
rollback 回滾(回到初始狀態)
-- 開啟一個事務
start transaction;
-- 或者使用(非標準sql)
begin;
insert into t values (1, 1, 1);
-- 事務結束,插入成功
commit;

begin;
insert into t values (2, 1, 1);
insert into t values (3, 1, 1);
insert into t values (4, 1, 1);
-- 事務結束,沒有插入數據
rollback;

begin;

insert into t values (1, 1, 1);
savepoint a1;
insert into t values (2, 1, 1);
-- 回滾到指定的保存點
rollback to a1;
commit;

自動提交

  • autocommit可以在session級別設置
  • 每個DML操作都自動提交
  • DDL永遠都是自動提交,無法通過rollback回滾

事務的四個基本屬性(ACID)

  • 原子性(Atomicity)
    一個事務包含多個操作,這些操作要么全部執行,要么全都不執行。實現事務的原子性,要支持回滾操作,在某個操作失敗后(數據庫或應用發生異常),回滾到事務執行之前的狀態。未提交的事務都應該被回滾。

  • 一致性(Consistency)

  • 數據的正確性,合理性,完整性

  • 數據一致性要符合應用應該符合的規則:余額不為負/交易對象必須先有賬號
    /用戶賬號不重復

  • 事務的結果需要滿足數據的一致性約束

  • 隔離性(Isolation)
    并發的事務是相互隔離的。數據庫的某一事務在提交完成前,中間的任何數據變化對其他的事務都是不可見的。
    即一個事務內部的操作及正在操作的數據必須封鎖起來,不被其它企圖進行修改的事務看到(假如并發交叉執行的多個事務任意操縱相同的共享對象,可能引起異常)

  • 持久性(Durability)
    發生故障時,確保已提交事務的更新不能丟失。
    一旦事務提交完成,對數據庫中數據的影響必須是永久性的(數據成功寫入磁盤 即 持久化成功)。

實現 事務的持久化

  • 數據文件持久化
    • 隨機同步刷新(慢)
  • 事務日志持久化與實例恢復
    • 順序同步刷新(快) -> 事務日志
    • 隨機異步刷新 -> 磁盤
    • 事務日志 -> 磁盤(實例恢復)

數據庫隔離現象

隔離現象 描述
臟讀(Dirty Read) 事務B讀到事務A尚未提交的數據變更
不可重復讀(NonRepeatable Read) 事務B讀取前后兩次讀取一條記錄之間該記錄被事務A修改并提交,于是事務B讀到了不一樣的結果
幻讀(Phantom Read) 事務B按條件匹配到了若干行記錄并修改。但是由于修改過程中事務A新插入了符合條件記錄,導致B更新完成后發現仍有符合條件卻未被更新的記錄。

數據庫隔離等級

隔離等級 臟讀 不可重復讀 幻讀
未提交讀(Read Uncommitted) 可能 可能 可能
已提交讀(Read Committed) 不可能 可能 可能
可重復讀(Repeated Read) 不可能 不可能 可能
可串行化讀(Serialization) 不可能 不可能 不可能

只有在事務提交后,其更新結果才會被其他事務看見。

 :在一個事務中,對于同一份數據的讀取結果總是相同的,無論是否有其他事務對這份數據進行操作

MySQL的事務隔離級別

  • InnoDB默認標記為可重復讀
  • InnoDB并不是標準定義上的課重復讀
  • InnoDB默認在可重復讀的基礎上避免幻讀

MySQL事務隔離級別設置

  • 可在global/session/下個事務,級別分別進行設置
  • 建議使用Read committed(同Oracle)
  • 或者建議使用默認的Repeatable read
set tx_isolation = ''
-- 設置隔離級別

事務與并發寫

  • 某個正在更新的記錄再提交或回滾前不能被其他事務同時更新

事務回滾的實現

  • 回滾段(rollback segment)與數據前像

3.2-存儲引擎概述

MySQL程序層次架構

./sorence/images/01.jpg

MySQL存儲引擎

  • 有多種可選方案,可插拔,可修改存儲引擎
  • 基于表選擇使用何種存儲引擎

主要存儲引擎

存儲引擎 常用度 支持事務
InnoDB 主要,推薦
MyISAM 古老,偶爾有用,系統表
MEMORY 偶爾臨時表有用,純內存
BLACKHOLE 不用來存放數據,個別特殊用處
TokuDB 新穎,個別特殊場景有奇效
Cluster 新穎,分布式,內存,線上不要用

InnoDB存儲引擎

  • 索引組織表
  • 支持事務
  • 支持行級鎖
  • 數據塊緩存
  • 日志持久化
  • 穩定可靠,性能好,線上盡量使用InnoDB

MyISAM存儲引擎

  • 堆表
  • 不支持事務
  • 只維護索引緩存池,表數據緩存交給操作系統
  • 鎖粒度較大
  • 數據文件可以直接拷貝,偶爾可能會用上
  • 不建議線上業務數據使用

MWMORY存儲引擎

  • 數據全內存存放,無法持久化
  • 性能較高
  • 不支持事務
  • 適合偶爾作為臨時表使用
  • create temporary table tmp (id int) engine = memory ;

BLACKHOLE存儲引擎

  • 數據不作任何存儲
  • 利用MySQL Replicate,充當日志服務器
  • 在MySQL Replicate環境中充當代理主

TokuDB

  • 分形樹存儲結構
  • 支持事務
  • 行鎖
  • 壓縮效率較高
  • 適合大批量insert的場景

MySQL Cluster

  • 多主分布式集群
  • 數據節點間冗余,高可用
  • 支持事務
  • 設計上易于擴展
  • 面向未來,線上慎用

改變表的存儲引擎

alter table m ENGINE=innodb;

3.3-InnoDB存儲引擎

InnoDB存儲引擎體系架構

/sorence/images/02.png

InnoDB相關的磁盤文件

文件 名稱 數量 位置
系統表空間 ibdata1 一個實例一個 innodb_data_home_dir
日志文件 ib_logfile0/1 一個實例兩個(可配置) innodb_log_group_home_dir
表定義文件 表名.frm 每張表一個 Schema目錄下
表數據文件 表名.ibd 如果innodb_file_per_table = 1, 則每張表一個 Schema目錄下

InnoDB系統表空間文件

  • ibdata1里存放了什么:
    • 回滾段
    • 所有InnoDB表元數據信息
    • Double Write, Insert buffer dump等等....
  • 自動擴展機制

InnoDB與磁盤文件有關的參數

參數 樣例值 備注
innodb_data_home_dir /data/mysql/node_1 數據主目錄
innodb_log_group_home_dir /data/mysql/node_1 一般同上
innodb_data_file_path ibdata1:512M:autoextned 請開啟autoextned
innodb_autoextend_increment 128 MB,勿太大或太小
innodb_file_per_table 1 強烈建議開啟
innodb_log_file_size 100MB 性能相關
innodb_log_files_in_group 2 性能相關

InnoDB數據文件存儲結構

  • 索引組織表(聚簇表)
  • 根據表邏輯主鍵排序
  • 數據節點每頁16K
  • 根據主鍵尋址速度很快
  • 主鍵值遞增的insert插入效率較好
  • 主鍵值隨機insert插入效率差
  • 因此,InnoDB表必須指定主鍵,建議使用自增數字

InnoDB數據塊緩存池

  • 數據的讀寫需要經過緩存
  • 數據以整頁(16K)為單位讀取到緩存中
  • 緩存中的數據以LRU策略換出
  • IO效率高,性能好

InnoDB Buffer Pool相關參數

參數 樣例值 備注
innodb_buffer_pool_size 10G 根據總物理內存設置

InnoDB數據持久化與事務日志

  • 事務日志實時持久化
  • 內存變化數據(臟數據)增量異步刷出到磁盤
  • 實例故障靠重放日志恢復
  • 性能好,可靠,恢復快

InnoDB日志持久化相關參數

參數 樣例值 備注
innodb_flush_log_at_trx_commit 1 可選:0:每隔1s寫入并持久化一次日志。1:每次commit都寫入并持久化日志。2:每次提交日志寫到內存,每1s持久化一次

InnoDB行級鎖

  • 寫不阻塞讀
  • 不同行間的寫互相不阻塞
  • 并發性能好

InnoDB與事務ACID

  • 事務ACID特性完整支持
    • 回滾段失敗回滾
    • 支持主外鍵約束
    • 事務版本+回滾段=MVCC
    • 事務日志持久化
  • 默認可重復讀隔離級別,可以調整

3.4-InnoDB事務鎖

什么是計算機程序鎖

  • 計算機程序鎖
    • 控制對共享資源進行并發訪問
    • 保護數據的完整性和一致性

數據庫中的鎖

  • 分為兩個大類
lock latch/mutex
對象 事務 線程
保護 數據庫邏輯內容 內存數據結構
持續時間 事務過程中 臨界資源爭搶
  • 我們主要關心的是事務鎖

數據庫事務并發

  • 對同一行記錄的修改必須串行化

事務鎖粒度

  • 行鎖
    • InnoDB, Oracle
  • 頁鎖
    • SQL Server
  • 表鎖
    • MyISAM, Memory
  • 鎖升級

InnoDB存儲引擎中的鎖模式與粒度

  • 四種基本鎖模式
    • 共享鎖(S) - 讀鎖 - 行鎖
    • 排他鎖(X) - 寫鎖 - 行鎖
    • 意向共享鎖(IS) - 表級
    • 意向排他鎖(IX) - 表級
  • 意向鎖
    • 意向鎖總是自動先加,并且意向鎖自動加自動釋放
    • 意向鎖提示數據庫這個session將要在接下來施加何種鎖
    • 意向鎖和X/S鎖級別不同,除了阻塞全表級別的X/S鎖外其他任何鎖

InnoDB鎖模式互斥

/sorence/images/03.png

數據庫加鎖操作

  • 一般的select語句不加任何鎖,也不會被任何事物鎖阻塞
    • 讀的隔離性由MVCC確保
  • S鎖
    • 手動:select * from tb_test lock in share mode;
    • 自動:insert前
  • X鎖
    • 手動:select * from tb_test lock for update;
    • 自動:update,delete前

InnoDB行鎖的實現

  • 通過索引項加鎖實現
    • 只有條件走索引才能實現行級鎖
    • 索引上有重復值,可能鎖住多個記錄
    • 查詢有多個索引可以走,可以對不同索引加鎖
    • 是否對索引加鎖實際上取決于MySQL執行計劃
  • 自增主鍵做條件更新,性能最好

沒有索引的話會對整張表加鎖。

InnoDB的gap lock

  • 什么是幻讀
  • gap lock消滅幻讀
    • InnoDB消滅幻讀僅僅為了確保statement模式replicate的主從一致性
  • 小心gap lock
  • 自增主鍵做條件更新,性能最好

死鎖

  • 什么是死鎖

    • A、B兩個事務,A先更新t1,同時B更新t2,A再更新t2,B再更新t1就發生了死鎖。
  • 死鎖數據庫自動解決

    • 數據庫挑選沖突事務中回滾代價較小的事務回滾
  • 死鎖預防

    • 單表死鎖可以根據批量更新里的更新條件排序
    • 可能沖突的跨表事務盡量避免并發
    • 盡量縮短事務長度

業務邏輯加鎖

  • 業務流程中的悲觀鎖

    • 任何的并發修改都有可能造成我們的業務邏輯最終的錯誤,在事務流程中一開始就加鎖,最后釋放
  • 如何縮短鎖的時間

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容