一、什麼是數據的存儲引擎?mysql
在實際工做中,選擇一個合適的存儲引擎是一個很複雜的問題。每種存儲引擎都有各自的優點,不能籠統的說誰比誰更好。下面將詳解不一樣環境常常用到的存儲引擎和針對各個存儲引擎的特色進行對比,給出不一樣的選擇建議。web
InnoDB是Mysql數據庫的一種存儲引擎。InnoDB給Mysql的表提供了 事務、回滾、崩潰修復能力、多版本併發控制的事務安全、間隙鎖(能夠有效的防止幻讀的出現)、支持輔助索引、聚簇索引、自適應hash索引、支持熱備、行級鎖。還有InnoDB是Mysql上惟一一個提供了外鍵約束的引擎。sql
InnoDB存儲引擎中,建立的表的表結構是單獨存儲的而且存儲在.frm文件中。數據和索引存儲在一塊兒的而且存儲在表空間中。可是默認狀況下mysql會將數據庫的全部InnoDB表存儲在一個表空間中的。其實這種方式管理起來很是的不方便並且還不支持高級功能因此建議每一個表存儲爲一個表空間實現方式爲:使用服務器變量innodb_file_per_table = 1。數據庫
若是須要頻繁的進行更新、刪除操做的數據庫也可選擇InnoDB存儲引擎。由於該存儲引擎能夠實現事務提交和回滾。緩存
MyISAM存儲引擎是Mysql中常見的存儲引擎,MyISAM存儲引擎是基於ISAM存儲引擎發展起來的。MyISAM支持全文索引、壓縮存放、空間索引(空間函數)、表級鎖、延遲更新索引鍵。可是MyISAM不支持事務、行級鎖、更沒法忍受的是崩潰後不能保證徹底恢復(只能手動修復)。安全
MyISAM存儲引擎的表存儲成3個文件。文件的名字和表的名字相同。擴展名包含frm、MYD、MYI。其中frm爲擴展名的文件存儲表的結構;MYD爲擴展名的文件存儲數據,其是MYData的縮寫;MYI爲擴展名的文件存儲索引,其爲MYIndex的縮寫。服務器
MyISAM存儲引擎的插入數據很快,空間和內存使用比較低。若是表主要是用於插入新記錄和讀出記錄,那麼選擇MyISAM存儲引擎可以實現處理的高效率。若是應用的完整性、併發性要求很低,也能夠選擇MyISAM存儲引擎。網絡
ARCHIVE,見名之意可看出是歸檔,因此歸檔以後不少的高級功能就再也不支持了僅支持插入(insert)和查詢(select)兩種功能, ARCHIVE存儲引擎以前還不支持索引(在Mysql5.5之後開始支持索引了),可是它擁有很好的壓縮機制。一般用於作倉庫使用。數據結構
ARCHIVE存儲引擎適用於存儲日誌信息或其餘按時間序列實現的數據採集類的應用場景中。併發
CSV是將數據文件保存爲CSV格式的的文件的,能夠方便的導入到其餘數據庫中去(例如:excel表格,SQLserver等等),由此須要在數據庫間自由共享數據時才偶爾建議使用此存儲引擎。而且它也不支持索引;我的認爲僅適用於數據交換。
BLACKHOLE叫作黑洞,也就是說沒有存儲機制,任何數據都會被丟棄,可是會記錄二進制日誌。通常在Mysql複製(中繼服務器)中常常用到,這個在Mysql複製博客中將詳細介紹,敬請關注。
FEDERATED能夠實現跨服務器整理表,簡單說就是它能夠訪問遠程服務器上數據的存儲引擎,因此說它再也不本地建立數據只會自動的創建一個鏈接到其餘服務器上連接,有點相似於代理的功能,默認都是禁用的。
MEMORY存儲引擎是Mysql中的一類特殊的存儲引擎。其使用存儲在內存中的內存來建立表,並且全部數據保存在內存中。數據安全性很低,可是查找和插入速度很快。若是內存出現異常就會影響到數據的完整性,若是重啓或關機,表中的全部數據就會丟失,所以基於MEMORY存儲引擎的表的生命週期很短,通常都是一次性的。適用於某些特殊場景像查找和映射,緩存週期性的聚合數據等等。
MRG_MYISAM存儲引擎是合併MyISAM表的,就是將多個MyISAM合併爲一個(在用戶看來是一個進行工做,實際上是多個底層物理文件在運行工做)。
鎖定
數據庫引擎中的鎖定功能決定了如何管理信息的訪問和更新。當數據庫中的一個對象爲信息更新鎖定了,在更新完成以前,其它處理不能修改這個數據(在某些狀況下還不容許讀這種數據)。
鎖定不只影響許多不一樣的應用程序如何更新數據庫中的信息,並且還影響對那個數據的查詢。這是由於查詢可能要訪問正在被修改或者更新的數據。總的來講,這種延遲是很小的。大多數鎖定機制主要是爲了防止多個處理更新同一個數據。因爲向數據中插入信息和更新信息這兩種狀況都須要鎖定,你能夠想象,多個應用程序使用同一個數據庫可能會有很大的影響。
不一樣的存儲引擎在不一樣的對象級別支持鎖定,並且這些級別將影響能夠同時訪問的信息。獲得支持的級別有三種:表鎖定、塊鎖定和行鎖定。支持最多的是表鎖定,這種鎖定是在MyISAM中提供的。在數據更新時,它鎖定了整個表。這就防止了許多應用程序同時更新一個具體的表。這對應用不少的多用戶數據庫有很大的影響,由於它延遲了更新的過程。
頁級鎖定使用Berkeley DB引擎,而且根據上載的信息頁(8KB)鎖定數據。當在數據庫的不少地方進行更新的時候,這種鎖定不會出現什麼問題。可是,因爲增長几行信息就要鎖定數據結構的最後8KB,當須要增長大量的行,也別是大量的小型數據,就會帶來問題。
行級鎖定提供了最佳的並行訪問功能,一個表中只有一行數據被鎖定。這就意味着不少應用程序可以更新同一個表中的不一樣行的數據,而不會引發鎖定的問題。只有InnoDB存儲引擎支持行級鎖定。
*修改存儲引擎,能夠用命令Alter table tableName engine =engineName
假如,若須要將表user的存儲引擎修改成archive類型,則可以使用命令alter table user engine=archive。
*建立數據庫表時設置存儲存儲引擎的基本語法是:
Create table tableName(
columnName(列名1) type(數據類型) attri(屬性設置),
columnName(列名2) type(數據類型) attri(屬性設置),
……..) engine = engineName
事物:
何爲數據庫事務 「一榮俱榮,一損俱損」這句話很能體現事務的思想,不少複雜的事物要分步進行,但它們組成一個總體,要麼總體生效,要麼總體失效。這種思想反映到數據庫上,就是多個SQL語句,要麼全部執行成功,要麼全部執行失敗。 數據庫事務有嚴格的定義,它必須同時知足四個特性:原子性(Atomic)、一致性(Consistency)、隔離性(Isolation)和持久性(Durabiliy),簡稱爲ACID。下面是對每一個特性的說明: 1. 原子性:表示組成一個事務的多個數據庫操做是一個不可分隔的原子單元,只有全部的操做執行成功,整個事務才提交,事務中任何一個數據庫操做失敗,已經執行的任何操做都必須撤銷,讓數據庫返回到初始狀態; 2. 一致性:事務操做成功後,數據庫所處的狀態和它的業務規則是一致的,即數據不會被破壞。如從A帳戶轉帳100元到B帳戶,無論操做成功與否,A和B的存款總額是不變的; 3. 隔離性:在併發數據操做時,不一樣的事務擁有各自數據空間,它們的操做不會對對方產生干擾。準確的說,並不是要求作到徹底無干擾,數據庫規定了多種事務隔離級別,不一樣隔離級別對應不一樣的干擾程度,隔離級別越高,數據一致性越好,但併發性越弱; 4. 持久性:一旦事務提交成功後,事務中全部的數據操做都必須被持久化到數據庫中,即便提交事務後,數據庫立刻崩潰,在數據庫重啓時,也必須能保證可以經過某種機制恢復數據。
在這些事務特性中,數據「一致性」是最終目標,其它的特性都是爲達到這個目標的措施、要求或手段。 數據庫管理系統通常採用重執行日誌保證原子性、一致性和持久性,重執行日誌記錄了數據庫變化的每個動做,數據庫在一個事務中執行一部分操做後發生錯誤退出,數據庫便可以根據重執行日誌撤銷已經執行的操做。此外,對於已經提交的事務,即便數據庫崩潰,在重啓數據庫時也可以根據日誌對還沒有持久化的數據進行相應的重執行操做。
和Java程序採用對象鎖機制進行線程同步相似,數據庫管理系統採用數據庫鎖機制保證事務的隔離性。當多個事務試圖對相同的數據進行操做時,只有持有鎖的事務才能操做數據,直到前一個事務完成後,後面的事務纔有機會對數據進行操做。Oracle數據庫還使用了數據版本的機制,在回滾段爲數據的每一個變化都保存一個版本,使數據的更改不影響數據的讀取。
數據併發的問題 一個數據庫可能擁有多個訪問客戶端,這些客戶端均可以併發方式訪問數據庫。數據庫中的相同數據可能同時被多個事務訪問,若是沒有采起必要的隔離措施,就會致使各類併發問題,破壞數據的完整性。這些問題能夠歸結爲5類,包括3類數據讀問題(髒讀、幻象讀和不可重複讀)以及2類數據更新問題(第一類丟失更新和第二類丟失更新)。下面,咱們分別經過實例講解引起問題的場景。
髒讀(dirty read) 在講解髒讀前,咱們先講一個笑話:一個有結巴的人在飲料店櫃檯前轉悠,老闆很熱情地迎上來:「喝一瓶?」,結巴連忙說:「我…喝…喝…」,老闆麻利地打開易拉罐遞給結巴,結巴終於憋出了他的那句話:「我…喝…喝…喝不起啊!」。在這個笑話中,飲料店老闆就對結巴進行了髒讀。 A事務讀取B事務還沒有提交的更改數據,並在這個數據的基礎上操做。若是恰巧B事務回滾,那麼A事務讀到的數據根本是不被認可的。來看取款事務和轉帳事務併發時引起的髒讀場景:
時間 | 轉帳事務A | 取款事務B |
T1 | 開始事務 | |
T2 | 開始事務 | |
T3 | 查詢帳戶餘額爲1000元 | |
T4 | 取出500元把餘額改成500元 | |
T5 | 查詢帳戶餘額爲500元(髒讀) | |
T6 | 撤銷事務餘額恢復爲1000元 | |
T7 | 匯入100元把餘額改成600元 | |
T8 | 提交事務 |
在這個場景中,B但願取款500元然後又撤銷了動做,而A往相同的帳戶中轉帳100元,就由於A事務讀取了B事務還沒有提交的數據,於是形成帳戶白白丟失了500元。在Oracle數據庫中,不會發生髒讀的狀況。
不可重複讀(unrepeatable read) 不可重複讀是指A事務讀取了B事務已經提交的更改數據。假設A在取款事務的過程當中,B往該帳戶轉帳100元,A兩次讀取帳戶的餘額發生不一致:
時間 | 取款事務A | 轉帳事務B |
T1 | 開始事務 | |
T2 | 開始事務 | |
T3 | 查詢帳戶餘額爲1000元 | |
T4 | 查詢帳戶餘額爲1000元 | |
T5 | 取出100元把餘額改成900元 | |
T6 | 提交事務 | |
T7 | 查詢帳戶餘額爲900元(和T4讀取的不一致) |
在同一事務中,T4時間點和T7時間點讀取帳戶存款餘額不同。
幻象讀(phantom read) A事務讀取B事務提交的新增數據,這時A事務將出現幻象讀的問題。幻象讀通常發生在計算統計數據的事務中,舉一個例子,假設銀行系統在同一個事務中,兩次統計存款帳戶的總金額,在兩次統計過程當中,恰好新增了一個存款帳戶,並存入100元,這時,兩次統計的總金額將不一致: 若是新增數據恰好知足事務的查詢條件,這個新數據就進入了事務的視野,於是產生了兩個統計不一致的狀況。
幻象讀和不可重複讀是兩個容易混淆的概念,前者是指讀到了其它已經提交事務的新增數據,然後者是指讀到了已經提交事務的更改數據(更改或刪除),爲了不這兩種狀況,採起的對策是不一樣的,防止讀取到更改數據,只須要對操做的數據添加行級鎖,阻止操做中的數據發生變化,而防止讀取到新增數據,則每每須要添加表級鎖——將整個表鎖定,防止新增數據(Oracle使用多版本數據的方式實現)。 第一類丟失更新 A事務撤銷時,把已經提交的B事務的更新數據覆蓋了。這種錯誤可能形成很嚴重的問題,經過下面的帳戶取款轉帳就能夠看出來:
時間 | 取款事務A | 轉帳事務B |
T1 | 開始事務 | |
T2 | 開始事務 | |
T3 | 查詢帳戶餘額爲1000元 | |
T4 | 查詢帳戶餘額爲1000元 | |
T5 | 匯入100元把餘額改成1100元 | |
T6 | 提交事務 | |
T7 | 取出100元把餘額改成900元 | |
T8 | 撤銷事務 | |
T9 | 餘額恢復爲1000元(丟失更新) |
A事務在撤銷時,「不當心」將B事務已經轉入帳戶的金額給抹去了。
第二類丟失更新 A事務覆蓋B事務已經提交的數據,形成B事務所作操做丟失:
時間 | 轉帳事務A | 取款事務B |
T1 | 開始事務 | |
T2 | 開始事務 | |
T3 | 查詢帳戶餘額爲1000元 | |
T4 | 查詢帳戶餘額爲1000元 | |
T5 | 取出100元把餘額改成900元 | |
T6 | 提交事務 | |
T7 | 匯入100元 | |
T8 | 提交事務 | |
T9 | 把餘額改成1100元(丟失更新) |
上面的例子裏因爲支票轉帳事務覆蓋了取款事務對存款餘額所作的更新,致使銀行最後損失了100元,相反若是轉帳事務先提交,那麼用戶帳戶將損失100元。
數據庫鎖機制 數據併發會引起不少問題,在一些場合下有些問題是容許的,但在另一些場合下可能倒是致命的。數據庫經過鎖的機制解決併發訪問的問題,雖然不一樣的數據庫在實現細節上存在差異,但原理基本上是同樣的。 按鎖定的對象的不一樣,通常能夠分爲表鎖定和行鎖定,前者對整個表進行鎖定,然後者對錶中特定行進行鎖定。從併發事務鎖定的關係上看,能夠分爲共享鎖定和獨佔鎖定。共享鎖定會防止獨佔鎖定,但容許其它的共享鎖定。而獨佔鎖定既防止其它的獨佔鎖定,也防止其它的共享鎖定。爲了更改數據,數據庫必須在進行更改的行上施加行獨佔鎖定,INSERT、UPDATE、DELETE和SELECT FOR UPDATE語句都會隱式採用必要的行鎖定。下面咱們介紹一下ORACLE數據庫經常使用的5種鎖定: l 行共享鎖定:通常經過SELECT FOR UPDATE語句隱式得到行共享鎖定,在Oracle中你也能夠經過LOCK TABLE IN ROW SHARE MODE語句顯式得到行共享鎖定。行共享鎖定並不防止對數據行進行更改的操做,可是能夠防止其它會話獲取獨佔性數據表鎖定。容許進行多個併發的行共享和行獨佔性鎖定,還容許進行數據表的共享或者採用共享行獨佔鎖定; l 行獨佔鎖定:經過一條INSERT、UPDATE或DELETE語句隱式獲取,或者經過一條LOCK TABLE IN ROW EXCLUSIVE MODE語句顯式獲取。這個鎖定能夠防止其它會話獲取一個共享鎖定、共享行獨佔鎖定或獨佔鎖定; l 表共享鎖定:經過LOCK TABLE IN SHARE MODE語句顯式得到。這種鎖定能夠防止其它會話獲取行獨佔鎖定(INSERT、UPDATE或DELETE),或者防止其它表共享行獨佔鎖定或表獨佔鎖定,它容許在表中擁有多個行共享和表共享鎖定。該鎖定可讓會話具備對錶事務級一致性訪問,由於其它會話在你提交或者回溯該事務並釋放對該表的鎖定以前不能更改這個被鎖定的表; l 表共享行獨佔:經過LOCK TABLE IN SHARE ROW EXCLUSIVE MODE語句顯式得到。這種鎖定能夠防止其它會話獲取一個表共享、行獨佔或者表獨佔鎖定,它容許其它行共享鎖定。這種鎖定相似於表共享鎖定,只是一次只能對一個表放置一個表共享行獨佔鎖定。若是A會話擁有該鎖定,則B會話能夠執行SELECT FOR UPDATE操做,但若是B會話試圖更新選擇的行,則須要等待; l 表獨佔:經過LOCK TABLE IN EXCLUSIVE MODE顯式得到。這個鎖定防止其它會話對該表的任何其它鎖定。
事務隔離級別 儘管數據庫爲用戶提供了鎖的DML操做方式,但直接使用鎖管理是很是麻煩的,所以數據庫爲用戶提供了自動鎖機制。只要用戶指定會話的事務隔離級別,數據庫就會分析事務中的SQL語句,而後自動爲事務操做的數據資源添加上適合的鎖。此外數據庫還會維護這些鎖,當一個資源上的鎖數目太多時,自動進行鎖升級以提升系統的運行性能,而這一過程對用戶來講徹底是透明的。 ANSI/ISO SQL 92標準定義了4個等級的事務隔離級別,在相同數據環境下,使用相同的輸入,執行相同的工做,根據不一樣的隔離級別,能夠致使不一樣的結果。不一樣事務隔離級別可以解決的數據併發問題的能力是不一樣的。 表 1 事務隔離級別對併發問題的解決狀況
隔離級別 | 髒讀 |
不可
重複讀
|
幻象讀 | 第一類丟失更新 | 第二類丟失更新 |
READ UNCOMMITED | 容許 | 容許 | 容許 | 不容許 | 容許 |
READ COMMITTED | 不容許 | 容許 | 容許 | 不容許 | 容許 |
REPEATABLE READ | 不容許 | 不容許 | 容許 | 不容許 | 不容許 |
SERIALIZABLE | 不容許 | 不容許 | 不容許 | 不容許 | 不容許 |
事務的隔離級別和數據庫併發性是對立的,二者此增彼長。通常來講,使用READ UNCOMMITED隔離級別的數據庫擁有最高的併發性和吞吐量,而使用SERIALIZABLE隔離級別的數據庫併發性最低。
SQL 92定義READ UNCOMMITED主要是爲了提供非阻塞讀的能力,Oracle雖然也支持READ UNCOMMITED,但它不支持髒讀,由於Oracle使用多版本機制完全解決了在非阻塞讀時讀到髒數據的問題並保證讀的一致性,因此,Oracle的READ COMMITTED隔離級別就已經知足了SQL 92標準的REPEATABLE READ隔離級別。
SQL 92推薦使用REPEATABLE READ以保證數據的讀一致性,不過用戶能夠根據應用的須要選擇適合的隔離等級。 JDBC對事務的支持 並非全部的數據庫都支持事務,即便支持事務的數據庫也並不是支持全部的事務隔離級別,你能夠經過Connection# getMetaData()方法獲取DatabaseMetaData對象,並經過該對象的supportsTransactions()、supportsTransactionIsolationLevel(int level)方法查看底層數據庫的事務支持狀況。Connection默認狀況下是自動提交的,也即每條執行的SQL都對應一個事務,爲了可以將多條SQL當成一個事務執行,必須先經過Connection#setAutoCommit(false)阻止Connection自動提交,並可經過Connection#setTransactionIsolation()設置事務的隔離級別,Connection中定義了對應SQL 92標準4個事務隔離級別的常量。經過Connection#commit()提交事務,經過Connection#rollback()回滾事務。下面是典型的JDBC事務數據操做的代碼: 代碼清單 1 JDBC事務代碼
在JDBC 2.0中,事務最終只能有兩個操做:要麼提交要麼回滾。可是,有些應用可能須要對事務進行更多的控制,而不是簡單地提交或回滾。JDBC 3.0(JDK 1.4及之後的版本)引入了一個全新的保存點特性,Savepoint 接口容許你將事務分割爲多個階段,你能夠指定回滾到事務的特定保存點,而非象JDBC 2.0同樣只回滾到開始事務的點,如圖 1所示:
圖 1 帶Savepoint的事務
下面的代碼使用了保存點的功能,在發生特定問題時,回滾到指定的保存點,則非回滾整個事務,如代碼清單 2所示: 代碼清單 2使用保存點的事務代碼
並不是全部數據庫都支持保存點功能,你能夠經過DatabaseMetaData#supportsSavepoints()方法查看是否支持。
小結 數據一致性和訪問的併發性二者之間的最佳平衡永遠是數據庫應用程序開發所追求的終極目錄。數據事務是保證數據訪問一致性的不二法門,使用API進行數據庫事務應用開發時,必須深入瞭解事務控制屬性對應用性能和數據一致性二者的影響,並根據項目實際須要進行合理的設置。