MySQL 事務提交 不良好的事務習慣。

2022-02-16 08:30:06 字數 3892 閱讀 4783

mysql 事務提交 --不良好的事務習慣

我們知道"事務"是資料庫區別於檔案系統的重要特性之一。mysql的innodb引擎中的事務也完全符合acid(原子性 一致性 隔離性 永續性)的特性。事務以及事務提交等一些內容不可避免的會出現在我們的日常工作當中。這篇文章我們就來簡單的聊聊一些不良好的事務習慣。

迴圈中提交事務

我們先來比較兩個儲存過程

create procedure load1 (count int unsigned)

begin

declare s int unsigned default 1;

declare c char(80) default repeat('a', 80);

while s <= count do

insert into t1 select null,c;

commit;

set s=s+1;

end while;

end;

create procedure load2(count int unsigned)

begin

declare s int unsigned default 1;

declare c char(80) default repeat('a', 80)

start transaction;

while s <= count do

insert into t1 select null,c;

set s = s+1;

end while;

commit;

end;

因為innodb儲存引擎預設是自動提交的,所以load1中如果去掉commit語句,結果也是一樣的。單純比較兩個儲存過程我們就可以知道,load1中存在乙個問題,例如當使用者需要插入10000條記錄,但是在插入第5000條時,發生了錯誤,這時前5000條記錄已經存放在資料庫中。而load2中整體都是放在乙個事務中,所以不會出現這個問題。除此之外,這兩個儲存過程的效能也存在差別,load2要比load1快出許多,這是因為每一次提交都要寫一次redo log,儲存過程load1實際上寫了10000次重做日誌,而對於儲存過程load2來說,實際只寫了1次redo log。因此執行時間會有巨大的差距。

在別的一些資料庫中,可能總是要求對事務盡快地釋放,不能有長時間的事務;其次,可能擔心存在oracle資料庫中由於沒有足夠undo產生的snapshot too old的經典問題。mysql的innodb引擎沒有上述的問題,因此無論是何種角度,都不應該在乙個迴圈中反覆進行提交操作,不論是顯式的還是隱式的提交。

使用自動提交

自動提交不是乙個好的習慣,因為這可能使開發人員產生錯誤的理解。我們可以使用如下語句來改變當前自動提交的方式:

set autocommit=0;
也可以使用start transaction, begin來顯式地開啟乙個事務。在顯式開啟事務後,在預設設定下(即引數completion_type等於0),mysql會自動地執行set autocommit=0的命令,並在commit或rollback結束乙個事務後執行set autocommit=1。此外對於不同語言的api,自動提交是不同的,因此在選用不同的語言來編寫資料庫應用程式前,應該對連線mysql的api做好研究。

使用自動回滾

innodb儲存引擎支援通過定義乙個handler來進行自動事務的回滾操作,如在乙個儲存過程中發生了錯誤會自動對其進行回滾操作。因此我發現很多開發人員喜歡在應用程式的儲存過程中使用自動回滾操作,例如下面所示的乙個儲存過程:

create table 'b' (

'a' int(11) not null default '0',

primary key ('a')

) engine=innodb default charset=latin1

create procedure sp_auto_rollback_demo()

begin

declare exit handler for sqlexception rollback;

start transaction;

insert into b select 1;

insert into b select 2;

insert into b select 1;

insert into b select 3;

commit;

end;

儲存過程sp_auto_rollback_demo首先定義了乙個exit型別的handler,當捕獲到錯誤時進行回滾。因此插入第二個記錄1時會發生錯誤,但是因為啟用了自動回滾操作,因此這個儲存過程的執行結果是沒有問題的,看起來非常正常。但我們並不能看出這個儲存過程的結果到底是正確還是錯誤的。為了得到執行正確與否的結果,開發人員可能會進行這樣的處理:

create procedure sp_auto_rollback_demo()

begin

declare exit handler for sqlexception rollback; select -1; end;

start transaction;

insert into b select 1;

insert into b select 2;

insert into b select 1;

insert into b select 3;

commit;

select 1;

end;

這樣如果發生錯誤,先回滾然後返回-1,表示執行有錯誤。執行正常返回值1。但是其實問題還是沒有解決,對開發人員來說,重要的不僅是知道是否發生了錯誤,還要知道發生了什麼錯誤。因此自動回滾存在這樣乙個問題。這裡其實有乙個建議是:對事務的begin,commit和rollback操作應該交給程式端來完成,儲存過程需要完成的只是乙個邏輯操作,即對邏輯進行封裝。在程式中控制事務的好處是,使用者可以得知發生錯誤的原因。長事務顧名思義,長事務是執行時間較長的事務。比如,對於銀行系統的資料庫,每過乙個階段可能需要更新對應賬戶的利息。如果對應賬號的數量非常大,例如對有1億使用者的表account,需要執行下列語句:

update account

set account_total = account_total + (1 + interest_rate)

這個事務可能需要非常長的時間來完成。由於事務acid的特性,這個操作被封裝在乙個事務中完成,這就產生了乙個問題,在執行過程中,當資料庫或作業系統,硬體等發生問題時,重新開始事務的代價變得不可接受。資料庫需要回滾所有已經發生的變化,而這個過程可能比產生這些變化的時間還要長。因此,對於長事務的問題,有時候可以通過轉化為小批量的事務來進行處理。當事務發生錯誤時,只需要回滾一部分資料,然後接著上次已經完成的事務繼續進行。

小結

事務是資料庫區別於檔案系統的乙個關鍵特性。事務必須遵循acid特性,即atomicity(原子性), consistency(一致性), isolation(隔離性) 和 durability(永續性)。隔離性通過鎖來完成,原子性,一致性,隔離性通過redo和undo來完成。在預設配置下,mysql innodb總是自動提交的,如果不知道這點,可能會帶來不好的結果。此外,在應用程式中,最好的做法是把事務的start transaction, commit, rollback操作交給程式段來完成,而不是在儲存過程中完成。

JAVA設定手動提交事務,回滾事務,提交事務

設定資料庫是否自動提交事務 param flag throws sqlexception public void setautocommit boolean flag throws sqlexception 提交 throws sqlexception public void commit thro...

事務與鎖定 提交事務

drop table emp if exists?create table emp empid number 5 empname varchar2 100 empage number 5 declare v empname varchar 50 chenzw begin delete from em...

MYSQL事務的開啟與提交

對於乙個mysql資料庫 innodb 事務的開啟與提交模式無非下面這兩種情況 1 若引數autocommit 0,事務則在使用者本次對資料進行操作時自動開啟,在使用者執行commit命令時提交,使用者本次對資料庫開始進行操作到使用者執行commit命令之間的一系列操作為乙個完整的事務週期。若不執行...