国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

mysql存儲過程事務管理簡析_MySQL

來源:懂視網 責編:小采 時間:2020-11-09 18:58:48
文檔

mysql存儲過程事務管理簡析_MySQL

mysql存儲過程事務管理簡析_MySQL:bitsCN.com ACID:Atomic、Consistent、Isolated、Durable 存儲程序提供了一個絕佳的機制來定義、封裝和管理事務。 1,MySQL的事務支持 1)MySQL的事務支持不是綁定在MySQL服務器本身,而是與存儲引擎相關: Sql代碼 MyISAM:不支持事務,用于只
推薦度:
導讀mysql存儲過程事務管理簡析_MySQL:bitsCN.com ACID:Atomic、Consistent、Isolated、Durable 存儲程序提供了一個絕佳的機制來定義、封裝和管理事務。 1,MySQL的事務支持 1)MySQL的事務支持不是綁定在MySQL服務器本身,而是與存儲引擎相關: Sql代碼 MyISAM:不支持事務,用于只

bitsCN.com ACID:Atomic、Consistent、Isolated、Durable
存儲程序提供了一個絕佳的機制來定義、封裝和管理事務。
1,MySQL的事務支持
1)MySQL的事務支持不是綁定在MySQL服務器本身,而是與存儲引擎相關:
Sql代碼

MyISAM:不支持事務,用于只讀程序提高性能
InnoDB:支持ACID事務、行級鎖、并發
Berkeley DB:支持事務
MyISAM:不支持事務,用于只讀程序提高性能
InnoDB:支持ACID事務、行級鎖、并發
Berkeley DB:支持事務 2) 隔離級別:

隔離級別決定了一個session中的事務可能對另一個session的影響、并發session對數據庫的操作、一個session中所見數據的一致性
ANSI標準定義了4個隔離級別,MySQL的InnoDB都支持:
Java代碼

READ UNCOMMITTED:最低級別的隔離,通常又稱為dirty read,它允許一個事務讀取還沒commit的數據,這樣可能會提高性能,但是dirty read可能不是我們想要的
READ COMMITTED:在一個事務中只允許已經commit的記錄可見,如果session中select還在查詢中,另一session此時insert一條記錄,則新添加的數據不可見
REPEATABLE READ:在一個事務開始后,其他session對數據庫的修改在本事務中不可見,直到本事務commit或rollback。在一個事務中重復select的結果一樣,除非本事務中update數據庫。
SERIALIZABLE:最高級別的隔離,只允許事務串行執行。為了達到此目的,數據庫會鎖住每行已經讀取的記錄,其他session不能修改數據直到前一事務結束,事務commit或取消時才釋放鎖。
READ UNCOMMITTED:最低級別的隔離,通常又稱為dirty read,它允許一個事務讀取還沒commit的數據,這樣可能會提高性能,但是dirty read可能不是我們想要的
READ COMMITTED:在一個事務中只允許已經commit的記錄可見,如果session中select還在查詢中,另一session此時insert一條記錄,則新添加的數據不可見
REPEATABLE READ:在一個事務開始后,其他session對數據庫的修改在本事務中不可見,直到本事務commit或rollback。在一個事務中重復select的結果一樣,除非本事務中update數據庫。
SERIALIZABLE:最高級別的隔離,只允許事務串行執行。為了達到此目的,數據庫會鎖住每行已經讀取的記錄,其他session不能修改數據直到前一事務結束,事務commit或取消時才釋放鎖。 可以使用如下語句設置MySQL的session隔離級別:

Sql代碼

set transaction isolation level {read uncommitted | read committed | repeatable read | serializable}
set transaction isolation level {read uncommitted | read committed | repeatable read | serializable}

MySQL默認的隔離級別是REPEATABLE READ,在設置隔離級別為READ UNCOMMITTED或SERIALIZABLE時要小心,READ UNCOMMITTED會導致數據完整性的嚴重問題,而SERIALIZABLE會導致性能問題并增加死鎖的機率
3)事務管理語句:
Sql代碼

START TRANSACTION:開始事務,autocommit設為0,如果已經有一個事務在運行,則會觸發一個隱藏的COMMIT
COMMIT:提交事務,保存更改,釋放鎖
ROLLBACK:回滾本事務對數據庫的所有更改,然后結束事務,釋放鎖
SAVEPOINT savepoint_name:創建一個savepoint識別符來ROLLBACK TO SAVEPOINT
ROLLBACK TO SAVEPOINT savepoint_name:回滾到從savepoint_name開始對數據庫的所有更改,這樣就允許回滾事務中的一部分,保證更改的一個子集被提交
SET TRANSACTION:允許設置事務的隔離級別
LOCK TABLES:允許顯式的鎖住一個或多個table,會隱式的關閉當前打開的事務,建議在執行LOCK TABLES語句之前顯式的commit或rollback。我們一般所以一般在事務代碼里不會使用LOCK TABLES
START TRANSACTION:開始事務,autocommit設為0,如果已經有一個事務在運行,則會觸發一個隱藏的COMMIT
COMMIT:提交事務,保存更改,釋放鎖
ROLLBACK:回滾本事務對數據庫的所有更改,然后結束事務,釋放鎖
SAVEPOINT savepoint_name:創建一個savepoint識別符來ROLLBACK TO SAVEPOINT
ROLLBACK TO SAVEPOINT savepoint_name:回滾到從savepoint_name開始對數據庫的所有更改,這樣就允許回滾事務中的一部分,保證更改的一個子集被提交
SET TRANSACTION:允許設置事務的隔離級別
LOCK TABLES:允許顯式的鎖住一個或多個table,會隱式的關閉當前打開的事務,建議在執行LOCK TABLES語句之前顯式的commit或rollback。我們一般所以一般在事務代碼里不會使用LOCK TABLES

2,定義事務
MySQL默認的行為是在每條SQL語句執行后執行一個COMMIT語句,從而有效的將每條語句獨立為一個事務。
在復雜的應用場景下這種方式就不能滿足需求了。
為了打開事務,允許在COMMIT和ROLLBACK之前多條語句被執行,我們需要做以下兩步(也可以人為是兩種方式):
1, 設置MySQL的autocommit屬性為0,默認為1
2,使用START TRANSACTION語句顯式的打開一個事務(然后autocommit屬性會自動被設置為0)
如果已經打開一個事務,則SET autocommit=0不會起作用,因為START TRANSACTION會隱式的提交session中所有當前的更改,結束已有的事務,并打開一個新的事務。
使用SET AUTOCOMMIT語句的存儲過程例子:
Sql代碼

delimiter $$
use test$$
create procedure t_insert_table()
begin
/** 標記是否出錯 */
declare t_error int default 0;
/** 如果出現sql異常,則將t_error設置為1后繼續執行后面的操作 */
declare continue handler for sqlexception set t_error=1; -- 出錯處理
/** 顯示的開啟事務,啟動它后,autocommit值會自動設置為0 */
start transaction;
insert into t_bom_test(parent_id,child_id) values('C','XXXX');
insert into t_trigger_test(name,age) values('zhangsan',34);
/** 標記被改變,表示事務應該回滾 */
if t_error=1 then
rollback; -- 事務回滾
else
commit; -- 事務提交
end if;
end$$
delimiter ;
delimiter $$
use test$$
create procedure t_insert_table()
begin
/** 標記是否出錯 */
declare t_error int default 0;
/** 如果出現sql異常,則將t_error設置為1后繼續執行后面的操作 */
declare continue handler for sqlexception set t_error=1; -- 出錯處理
/** 顯示的開啟事務,啟動它后,autocommit值會自動設置為0 */
start transaction;
insert into t_bom_test(parent_id,child_id) values('C','XXXX');
insert into t_trigger_test(name,age) values('zhangsan',34);
/** 標記被改變,表示事務應該回滾 */
if t_error=1 then
rollback; -- 事務回滾
else
commit; -- 事務提交
end if;
end$$
delimiter ;

通常COMMIT或ROLLBACK語句執行時才完成一個事務,但是有些DDL語句等會隱式觸發COMMIT,所以應該在事務中盡可能少用或注意一下:
Sql代碼

ALTER FUNCTION
ALTER PROCEDURE
ALTER TABLE
BEGIN
CREATE DATABASE
CREATE FUNCTION
CREATE INDEX
CREATE PROCEDURE
CREATE TABLE
DROP DATABASE
DROP FUNCTION
DROP INDEX
DROP PROCEDURE
DROP TABLE
UNLOCK TABLES
LOAD MASTER DATA
LOCK TABLES
RENAME TABLE
TRUNCATE TABLE
SET AUTOCOMMIT=1
START TRANSACTION
ALTER FUNCTION
ALTER PROCEDURE
ALTER TABLE
BEGIN
CREATE DATABASE
CREATE FUNCTION
CREATE INDEX
CREATE PROCEDURE
CREATE TABLE
DROP DATABASE
DROP FUNCTION
DROP INDEX
DROP PROCEDURE
DROP TABLE
UNLOCK TABLES
LOAD MASTER DATA
LOCK TABLES
RENAME TABLE
TRUNCATE TABLE
SET AUTOCOMMIT=1
START TRANSACTION

3,使用Savepoint
使用savepoint回滾難免有些性能消耗,一般可以用IF改寫
savepoint的良好使用的場景之一是“嵌套事務”,你可能希望程序執行一個小的事務,但是不希望回滾外面更大的事務:
Sql代碼

CREATE PROCEDURE nested_tfer_funds
(in_from_acct INTEGER,
in_to_acct INTEGER,
in_tfer_amount DECIMAL(8,2))
BEGIN
DECLARE txn_error INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN
SET txn_error=1;
END
SAVEPINT savepint_tfer;
UPDATE account_balance
SET balance=balance-in_tfer_amount
WHERE account_id=in_from_acct;
IF txn_error THEN
ROLLBACK TO savepoint_tfer;
SELECT 'Transfer aborted';
ELSE
UPDATE account_balance
SET balance=balance+in_tfer_amount
WHERE account_id=in_to_acct;
IF txn_error THEN
ROLLBACK TO savepoint_tfer;
SELECT 'Transfer aborted';
END IF:
END IF;
END;
CREATE PROCEDURE nested_tfer_funds
(in_from_acct INTEGER,
in_to_acct INTEGER,
in_tfer_amount DECIMAL(8,2))
BEGIN
DECLARE txn_error INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN
SET txn_error=1;
END
SAVEPINT savepint_tfer;
UPDATE account_balance
SET balance=balance-in_tfer_amount
WHERE account_id=in_from_acct;
IF txn_error THEN
ROLLBACK TO savepoint_tfer;
SELECT 'Transfer aborted';
ELSE
UPDATE account_balance
SET balance=balance+in_tfer_amount
WHERE account_id=in_to_acct;
IF txn_error THEN
ROLLBACK TO savepoint_tfer;
SELECT 'Transfer aborted';
END IF:
END IF;
END;

4,事務和鎖
事務的ACID屬性只能通過限制數據庫的同步更改來實現,從而通過對修改數據加鎖來實現。
直到事務觸發COMMIT或ROLLBACK語句時鎖才釋放。
缺點是后面的事務必須等前面的事務完成才能開始執行,吞吐量隨著等待鎖釋放的時間增長而遞減。
MySQL/InnoDB通過行級鎖來最小化鎖競爭。這樣修改同一table里其他行的數據沒有限制,而且讀數據可以始終沒有等待。
可以在SELECT語句里使用FOR UPDATE或LOCK IN SHARE MODE語句來加上行級鎖
Sql代碼

SELECT select_statement options [FOR UPDATE|LOCK IN SHARE MODE]
SELECT select_statement options [FOR UPDATE|LOCK IN SHARE MODE]

FOR UPDATE會鎖住該SELECT語句返回的行,其他SELECT和DML語句必須等待該SELECT語句所在的事務完成
LOCK IN SHARE MODE同FOR UPDATE,但是允許其他session的SELECT語句執行并允許獲取SHARE MODE鎖
死鎖:
死鎖發生于兩個事務相互等待彼此釋放鎖的情景
當MySQL/InnoDB檢查到死鎖時,它會強制一個事務rollback并觸發一條錯誤消息
對InnoDB而言,所選擇的rollback的事務是完成工作最少的事務(所修改的行最少)
Java代碼

mysql > CALL tfer_funds(1,2,300);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

死鎖在任何數據庫系統里都可能發生,但是對MySQL/InnoDB這種行級鎖數據庫而言可能性相對較少。
可以通過使用一致的順序來鎖row或table以及讓事務保持盡可能短來減少死鎖的頻率。
如果死鎖不容易debug,你可以向你的程序中添加一些邏輯來處理死鎖并重試事務,但這部分代碼多了以后很難維護
所以,比較好的避免死鎖的方式是在做任何修改之前按一定的順序添加行級鎖,這樣就能避免死鎖:
Java代碼

CREATE PROCEDURE tfer_funds3
(from_account INT, to_account INT, tfer_amount NUMERIC(10,2))
BEGIN
DECLARE local_account_id INT;
DECLARE lock_cursor CURSOR FOR
SELECT account_id
FROM account_balance
WHERE account_id IN (from_account, to_account)
ORDER BY account_id
FOR UPDATE;
START TRANSACTION;
OPEN lock_cursor;
FETCH lock_cursor INTO local_account_id;
UPDATE account_balance
SET balance=balance-tfer_amount
WHERE account_id=from_account;
UPDATE account_balance
SET balance=balance+tfer_amount
WHERE account_id=to_account;
CLOSE lock_cursor;
COMMIT;
END;

設置死鎖ttl: innodb_lock_wait_timeout,默認為50秒
如果你在一個事務中混合使用InnoDB和非InnoDB表,則MySQL不能檢測到死鎖,此時會拋出“lock wait timeuot”1205錯誤
樂觀所和悲觀鎖策略:
悲觀鎖:在讀取數據時鎖住那幾行,其他對這幾行的更新需要等到悲觀鎖結束時才能繼續
樂觀所:讀取數據時不鎖,更新時檢查是否數據已經被更新過,如果是則取消當前更新
一般在悲觀鎖的等待時間過長而不能接受時我們才會選擇樂觀鎖
悲觀鎖的例子:
Java代碼

CREATE PROCEDURE tfer_funds
(from_account INT, to_account INT,tfer_amount NUMERIC(10,2),
OUT status INT, OUT message VARCHAR(30))
BEGIN
DECLARE from_account_balance NUMERIC(10,2);
START TRANSACTION;
SELECT balance
INTO from_account_balance
FROM account_balance
WHERE account_id=from_account
FOR UPDATE;
IF from_account_balance>=tfer_amount THEN
UPDATE account_balance
SET balance=balance-tfer_amount
WHERE account_id=from_account;
UPDATE account_balance
SET balance=balance+tfer_amount
WHERE account_id=to_account;
COMMIT;
SET status=0;
SET message='OK';
ELSE
ROLLBACK;
SET status=-1;
SET message='Insufficient funds';
END IF;
END;

樂觀鎖的例子:
Java代碼

CREATE PROCEDURE tfer_funds
(from_account INT, to_account INT, tfer_amount NUMERIC(10,2),
OUT status INT, OUT message VARCHAR(30) )
BEGIN
DECLARE from_account_balance NUMERIC(8,2);
DECLARE from_account_balance2 NUMERIC(8,2);
DECLARE from_account_timestamp1 TIMESTAMP;
DECLARE from_account_timestamp2 TIMESTAMP;
SELECT account_timestamp,balance
INTO from_account_timestamp1,from_account_balance
FROM account_balance
WHERE account_id=from_account;
IF (from_account_balance>=tfer_amount) THEN
-- Here we perform some long running validation that
-- might take a few minutes */
CALL long_running_validation(from_account);
START TRANSACTION;
-- Make sure the account row has not been updated since
-- our initial check
SELECT account_timestamp, balance
INTO from_account_timestamp2,from_account_balance2
FROM account_balance
WHERE account_id=from_account
FOR UPDATE;
IF (from_account_timestamp1 <> from_account_timestamp2 OR
from_account_balance <> from_account_balance2) THEN
ROLLBACK;
SET status=-1;
SET message=CONCAT("Transaction cancelled due to concurrent update",
" of account" ,from_account);
ELSE
UPDATE account_balance
SET balance=balance-tfer_amount
WHERE account_id=from_account;
UPDATE account_balance
SET balance=balance+tfer_amount
WHERE account_id=to_account;
COMMIT;
SET status=0;
SET message="OK";
END IF;
ELSE
ROLLBACK;
SET status=-1;
SET message="Insufficient funds";
END IF;
END$$

5,事務設計指南
1,保持事務短小
2,盡量避免事務中rollback
3,盡量避免savepoint
4,默認情況下,依賴于悲觀鎖
5,為吞吐量要求苛刻的事務考慮樂觀鎖
6,顯示聲明打開事務
7,鎖的行越少越好,鎖的時間越短越好bitsCN.com

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

mysql存儲過程事務管理簡析_MySQL

mysql存儲過程事務管理簡析_MySQL:bitsCN.com ACID:Atomic、Consistent、Isolated、Durable 存儲程序提供了一個絕佳的機制來定義、封裝和管理事務。 1,MySQL的事務支持 1)MySQL的事務支持不是綁定在MySQL服務器本身,而是與存儲引擎相關: Sql代碼 MyISAM:不支持事務,用于只
推薦度:
標簽: 程序 服務器 mysql
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 欧美在线视频免费观看 | 精品一区 二区三区免费毛片 | 97久久精品午夜一区二区 | 国产精品不卡 | 欧洲毛片| 最新国产精品亚洲二区 | 一级a毛片免费观看久久精品 | 欧美地区一二三 | 精品在线免费观看 | 欧美日韩一 | 日韩高清一区二区 | 久久精品美女 | 亚洲欧美另类自拍 | 久久久毛片 | 中文字幕美日韩在线高清 | 国产一区二区不卡视频 | h免费视频| 国产日韩在线看 | 亚洲欧美在线免费观看 | 韩日一区二区 | 国产欧美第一页 | 亚洲一区二区三区四区在线观看 | 亚洲 欧美 日韩 另类 | 亚洲午夜一区二区三区 | 日韩电影免费在线观看网址 | 国产成人一区二区三区免费观看 | 91精品国产91久久久久 | 天天欧美 | 午夜国产大片免费观看 | 亚洲精品99久久久久中文字幕 | 一级不卡毛片免费 | 国产91精品久久久久久 | 国产香蕉视频在线观看 | 亚洲综合色婷婷 | 亚洲精品国产精品国自产观看 | 正在播放国产一区 | 国产亚洲欧美在线人成aaaa | 欧美国产日韩在线播放 | 欧美网站在线看 | 久久精品99久久香蕉国产色戒 | 精品69久久久久久99 |