[轉]mysql事務處理用法與實例詳解

轉自:http://www.cnblogs.com/ymy124/p/3718439.htmljavascript

 

MySQL的事務支持不是綁定在MySQL服務器自己,而是與存儲引擎相關1.MyISAM:不支持事務,用於只讀程序提升性能 2.InnoDB:支持ACID事務、行級鎖、併發 3.Berkeley DB:支持事務
 
 一個事務是一個連續的一組 數據庫操做,就好像它是一個單一的工做單元進行。換言之,永遠不會是完整的事務,除非該組內的每一個單獨的操做是成功的。若是在事務的任何操做失敗,則整個事務將失敗。

實際上,會俱樂部許多SQL查詢到一個組中,將執行全部的人都一塊兒做爲事務的一部分。php

事務的特性: 
事務有如下四個標準屬性的縮寫ACID,一般被稱爲:html

原子性: 確保工做單元內的全部操做都成功完成,不然事務將被停止在故障點,和之前的操做將回滾到之前的狀態。java

一致性: 確保數據庫正確地改變狀態後,成功提交的事務。mysql

隔離性: 使事務操做彼此獨立的和透明的。sql

持久性: 確保提交的事務的結果或效果的系統出現故障的狀況下仍然存在。數據庫

在MySQL中,事務開始使用COMMIT或ROLLBACK語句開始工做和結束。開始和結束語句的SQL命令之間造成了大量的事務。編程

COMMIT & ROLLBACK: 
這兩個關鍵字提交和回滾主要用於MySQL的事務。安全

當一個成功的事務完成後,發出COMMIT命令應使全部參與表的更改纔會生效。服務器

若是發生故障時,應發出一個ROLLBACK命令返回的事務中引用的每個表到之前的狀態。

能夠控制的事務行爲稱爲AUTOCOMMIT設置會話變量。若是AUTOCOMMIT設置爲1(默認值),而後每個SQL語句(在事務與否)被認爲是一個完整的事務,並承諾在默認狀況下,當它完成。 AUTOCOMMIT設置爲0時,發出SET AUTOCOMMIT =0命令,在隨後的一系列語句的做用就像一個事務,直到一個明確的COMMIT語句時,沒有活動的提交。

能夠經過使用mysql_query()函數在PHP中執行這些SQL命令。

通用事務例子 
這一系列事件是獨立於所使用的編程語言,能夠創建在任何使用的語言來建立應用程序的邏輯路徑。
能夠經過使用mysql_query()函數在PHP中執行這些SQL命令。


BEGIN WORK開始事務發出SQL命令

發出一個或多個SQL命令,如SELECT,INSERT,UPDATE或DELETE

檢查是否有任何錯誤,一切都依據的須要。

若是有任何錯誤,那麼問題ROLLBACK命令,不然發出COMMIT命令。

在MySQL中的事務安全表類型:

若是打算使用MySQL事務編程,那麼就須要一種特殊的方式建立表。有不少支持事務但最流行的是InnoDB表類型。

從源代碼編譯MySQL時,InnoDB表支持須要特定的編譯參數。若是MySQL版本沒有InnoDB支持,請互聯網服務提供商創建一個版本的MySQL支持InnoDB表類型,或者下載並安裝Windows或Linux/UNIX的MySQL-Max二進制分發和使用的表類型在開發環境中。
若是MySQL安裝支持InnoDB表,只需添加一個的TYPE=InnoDB 定義表建立語句。例如,下面的代碼建立InnoDB表tcount_tbl:

 

 代碼以下 複製代碼
root@host# mysql -u root -p password;
Enter password:*******
mysql> use TUTORIALS;
Database changed
mysql> create table tcount_tbl
    -> (
    -> tutorial_author varchar(40) NOT NULL,
    -> tutorial_count  INT
    -> ) TYPE=InnoDB;
Query OK, 0 rows affected (0.05 sec)

可使用其餘GEMINI或BDB表類型,但它取決於您的安裝,若是它支持這兩種類型。


因爲項目設計裏面,牽扯到了金錢的轉移,因而就要用到MYSQL的事務處理,來保證一組處理結果的正確性。用了事務,就不可避免的要犧牲一部分速度,來保證數據的正確性。
只有InnoDB支持事務

事務 ACID Atomicity(原子性)、Consistency(穩定性)、Isolation(隔離性)、Durability(可靠性)

一、事務的原子性
一組事務,要麼成功;要麼撤回。

二、穩定性
有非法數據(外鍵約束之類),事務撤回。

三、隔離性
事務獨立運行。
一個事務處理後的結果,影響了其餘事務,那麼其餘事務會撤回。
事務的100%隔離,須要犧牲速度。

四、可靠性
軟、硬件崩潰後,InnoDB數據表驅動會利用日誌文件重構修改。
可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit選項 決定何時吧事務保存到日誌裏。
開啓事務
START TRANSACTION 或 BEGIN

提交事務(關閉事務)
COMMIT

放棄事務(關閉事務)
ROLLBACK

折返點
SAVEPOINT adqoo_1
ROLLBACK TO SAVEPOINT adqoo_1
發生在折返點 adqoo_1 以前的事務被提交,以後的被忽略

事務的終止

設置「自動提交」模式
SET AUTOCOMMIT = 0
每條SQL都是同一個事務的不一樣命令,之間由 COMMIT 或 ROLLBACK隔開
掉線後,沒有 COMMIT 的事務都被放棄

事務鎖定模式

系統默認: 不須要等待某事務結束,可直接查詢到結果,但不能再進行修改、刪除。
缺點:查詢到的結果,多是已通過期的。
優勢:不須要等待某事務結束,可直接查詢到結果。

須要用如下模式來設定鎖定模式

一、SELECT …… LOCK IN SHARE MODE(共享鎖)
查詢到的數據,就是數據庫在這一時刻的數據(其餘已commit事務的結果,已經反應到這裏了)
SELECT 必須等待,某個事務結束後才能執行

二、SELECT …… FOR UPDATE(排它鎖)
例如 SELECT * FROM tablename WHERE id<200
那麼id<200的數據,被查詢到的數據,都將不能再進行修改、刪除、SELECT …… LOCK IN SHARE MODE操做
一直到此事務結束

共享鎖 和 排它鎖 的區別:在因而否阻斷其餘客戶發出的 SELECT …… LOCK IN SHARE MODE命令

三、INSERT / UPDATE / DELETE
全部關聯數據都會被鎖定,加上排它鎖

四、防插入鎖
例如 SELECT * FROM tablename WHERE id>200
那麼id>200的記錄沒法被插入

五、死鎖
自動識別死鎖
先進來的進程被執行,後來的進程收到出錯消息,並按ROLLBACK方式回滾
innodb_lock_wait_timeout = n 來設置最長等待時間,默認是50秒

事務隔離模式

SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL
READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE
一、不帶SESSION、GLOBAL的SET命令
只對下一個事務有效
二、SET SESSION
爲當前會話設置隔離模式
三、SET GLOBAL
爲之後新建的全部MYSQL鏈接設置隔離模式(當前鏈接不包括在內)

隔離模式

   READ UNCOMMITTED
不隔離SELECT
其餘事務未完成的修改(未COMMIT),其結果也考慮在內

   READ COMMITTED
把其餘事務的 COMMIT 修改考慮在內
同一個事務中,同一 SELECT 可能返回不一樣結果

   REPEATABLE READ(默認)
不把其餘事務的修改考慮在內,不管其餘事務是否用COMMIT命令提交過
同一個事務中,同一 SELECT 返回同一結果(前提是本事務,不修改)

   SERIALIZABLE
和REPEATABLE READ相似,給全部的SELECT都加上了 共享鎖

出錯處理
根據出錯信息,執行相應的處理


mysql事物處理實例

MYSQL的事務處理主要有兩種方法
1.用begin,rollback,commit來實現
    begin開始一個事務
    rollback事務回滾
    commit 事務確認
2.直接用set來改變mysql的自動提交模式
    mysql默認是自動提交的,也就是你提交一個query,就直接執行!能夠經過
    set autocommit = 0 禁止自動提交
    set autocommit = 1 開啓自動提交
    來實現事務的處理。
但要注意當用set autocommit = 0 的時候,你之後全部的sql都將做爲事務處理,直到你用commit確認或 rollback結束,注意當你結束這個事務的同時也開啓了新的事務!按第一種方法只將當前的作爲一個事務!
MYSQL只有 INNODB和BDB類型的數據表才支持事務處理,其餘的類型是不支持的!
MYSQL5.0 WINXP下測試經過~  ^_^

 代碼以下 複製代碼

    mysql> use test;
    Database changed
    mysql> CREATE TABLE `dbtest`(
    -> id int(4)
    -> ) TYPE=INNODB;
Query OK, 0 rows affected, 1 warning (0.05 sec)

mysql> select * from dbtest
    -> ;
Empty set (0.01 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into dbtest values(5);
Query OK, 1 row affected (0.00 sec)

mysql> insert into dbtest value(6);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from dbtest;
+------+
| id   |
+------+
|    5 |
|    6 |
+------+
2 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into dbtest values(7);
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from dbtest;
+------+
| id   |
+------+
|    5 |
|    6 |
+------+
2 rows in set (0.00 sec)

mysql> mysql事務處理

php代碼實現事務的處理能夠經過PHP預約義類mysqli的如下方法實現。
autocommit(boolean):該方法用於限定查詢結果是否自動提交,若是該方法的參數爲true則自動提交,若是參數爲false則關閉自動提交。MySQL數據庫默認爲自動提交。
rollback():利用mysqli類中的該方法能夠實現事務的回滾。
commit():利用該方法能夠實現提交全部查詢。

 代碼以下 複製代碼

<?php
include_once("conn.php");

$id=$_GET[id];
$conn->autocommit(false);
if(!$conn->query("delete from tb_sco where id='".$id."'"))
{
  $conn->rollback();
}
if(!$conn->query("delete from tb_stu where id='".$id."'"))
{
  $conn->rollback();
}
  $conn->commit();
  $conn->autocommit(true);
  echo "ok"
?>

列二

 代碼以下 複製代碼
<?php
require('connectDB.php'); //創建數據庫鏈接
mssql_query("BEGIN TRANSACTION DEPS02_DEL"); //開始事務
$delete_dep_sql="DELETE FROM TBLDEPARTMENT WHERE DEPTID='{$_GET[deptid]}'";
// echo $delete_dep_sql."<br>";
mssql_query($delete_dep_sql); //操做數據庫
// var_dump($del_result);
$delete_result = mssql_query("select @@ROWCOUNT as id");
$delete_info = mssql_fetch_array($delete_result);
$delete_rows = $delete_info[0];
// var_dump($delete_rows);
mssql_free_result($delete_result);
echo "<script language=javascript>";
if(true){    //判斷是否回滾提交
mssql_query("COMMIT TRANSACTION DEPS02_DEL"); //提交事務
echo "alert('delete success!');";
}else{
mssql_query("ROLLBACK TRANSACTION DEPS02_DEL"); //回滾事務
echo "alert('delete faile!');";
}
echo "</script>";mssql_close();
?>

例3

  MySQL的事務處理在處理實際問題中有着普遍且重要的應用,最多見的應用如銀行轉帳業務、電子商務支付業務等等。可是,值得注意的是,MySQL的事務處理功能在MYSIAM存儲引擎中是不支持的,在InnoDB存儲引擎中是支持的。如今上傳一段代碼,做爲引導認識MySQL事務處理的開始,簡單的實例,但融匯思想,相信會有很大的幫助。

 代碼以下 複製代碼

<?php
$conn=mysql_connect('localhost','root','yourpassword')or die(mysql_error());
mysql_select_db('transaction',$conn);
mysql_query('set names utf8');

//建立事務
mysql_query('START TRANSACTION') or die(mysql_error());
$sqlA="update A set account=account-1";
if(!mysql_query($sqlA)){
&nbsp;&nbsp;&nbsp; mysql_query('ROLLBACK') or exit(mysql_error());//判斷當執行失敗時回滾
&nbsp;   exit();
}
$sqlB="update B set account=account+1";
if(!mysql_query($sqlB)){
&nbsp;&nbsp;&nbsp; mysql_query('ROLLBACK') or exit(mysql_error());//判斷當執行失敗時回滾
&nbsp;   exit();
}
mysql_query('COMMIT')or die(mysql_error());//執行事務
mysql_close($conn);
?>

  以上代碼能夠做爲模擬銀行轉帳業務的事務流程。以表A、B分別表示兩個已在銀行開戶的帳戶,當帳戶A執行轉出1元給帳戶B的操做時,若是操做執行失敗,轉出將會回滾至原始狀態,不繼續向下執行動做。反之,若是操做執行成功,則帳戶B可用餘額將增長1元,不然事務回滾至原始狀態。

相關文章
相關標籤/搜索