天天看點

php mysql事務詳解

事務(transaction)及其acid屬性

事務是由一組sq語句組成的邏輯處理單元,事務具有以下4個屬性,通常簡稱為事務的acid屬性。

原子性(atomicity):事務是一個原子操作單元,其對資料的修改,要麼全都執行,要麼全都不執行。

持久性(durabe):事務完成之後,它對于資料的修改是永久性的,即使出現系統故障也能夠保持。

事物一般和異常處理結合

php mysql事務詳解

<?php  

$lnk = mysql_connect("localhost", "root", "");  

mysql_select_db("test");  

mysql_query("begin");  

try {  

    mysql_query("insert into test values(1, 'yangjun')");  

    mysql_query("insert into test values(2, '楊俊')");  

    mysql_query("commit"); //全部成功,送出執行結果  

}catch (exception $e){  

    //$e->getmessage();  

    mysql_query("rollback"); //有任何錯誤發生,復原并取消執行結果  

}  

在這裡要注意,

myisam:不支援事務 ,用于隻讀程式提高性能

innodb:支援acid事務、行級鎖、并發

berkeley db:支援事務

但往往,我們需要在使用事務的時候,是需要執行多條sql語句的。這就需要我們手動設定mysql的autocommit屬性為0,預設為1。

同時,使用start transaction語句顯式的打開一個事務 。如上面的示例。

如果不這樣做,會有什麼結果呢?

我們将上面第二段代碼中 //mysql_query(‘set autocommit=0′); 和 // mysql_query($sql3); 注釋去掉,然後執行。

此時,mysql_query($sql3) 執行就不會insert到資料庫中。

php mysql事務詳解

//對于不支援事務的myisam引擎資料庫可以使用表鎖定的方法:  

$sql_1=" lock tables test write ";  

mysql_query($sql_1);  

$sql_2=" insert into test values('".$a."','".$b."') ";  

if(mysql_query($sql_2)){  

  echo 'successful!';  

}else{  

  echo 'unsuccessful!';  

 }  

$sql_3=" unlock tables ";  

mysql_query($sql_3);   

如果我們将 // mysql_query(‘set autocommit=1′); 本句注釋去掉,那麼mysql_query($sql3); 就會執行成功。

通常commit或rollback語句執行時才完成一個事務,但是有些ddl語句等會隐式觸發commit。

比如下列語句

php mysql事務詳解

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  

 我們再來舉個例子看下。

php mysql事務詳解

$sql1 = 'create table scoredetail_new(id int)';  

$sql2 = 'rename table scoredetail to scoredetail_bak';  

$sql3  = 'rename table scoredetail_new to scoredetail';  

$mysqli = new mysqli('localhost','root','','db_lib2test');  

$mysqli->autocommit(false);//開始事物  

$mysqli->query($sql1);  

$mysqli->query($sql2);  

$mysqli->query($sql3);  

if(!$mysqli->errno){  

  $mysqli->commit();  

  echo 'ok';  

 echo 'err';  

  $mysqli->rollback();  

在上面的示例中,假如$sql2執行出錯了,$sql1照樣會執行的。為什麼呢?

因為rename在執行的時候,mysql預設會先執行commit,再執行rename。

mysql不支援嵌套事務

php mysql事務詳解

set autocommit=0;   

start transaction ;   

insert into person (firstname,lastname) values ('tr1','tr2');   

    start transaction ;   

    --這個時候前一個事務已經被commit了. insert了一次.   

    insert into person (firstname,lastname) values ('tr1','tr2');   

    commit;   

    --又insert了一遍   

rollback;   

start transaction:開始事務,如果已經有一個事務在運作,則會觸發一個隐藏的commit . 

用savepoint事物嵌套

php mysql事務詳解

mysql> update books set free =1, new=1;  

query ok, 0 rows affected (0.06 sec)  

rows matched: 79  changed: 0  warnings: 0  

mysql> commit;  

query ok, 0 rows affected (0.00 sec)  

mysql> set autocommit=1;  

mysql> begin;   

mysql> select free, new from books limit 1;  

+------+-----+  

| free | new |  

|    1 |   1 |  

1 row in set (0.00 sec)  

mysql> update books set free = 0;  

query ok, 79 rows affected (0.01 sec)  

rows matched: 79  changed: 79  warnings: 0  

|    0 |   1 |  

mysql> savepoint book1;  

mysql> update books set new = 0;  

query ok, 79 rows affected (0.00 sec)  

|    0 |   0 |  

mysql> rollback to book1;  

mysql> rollback;  

query ok, 0 rows affected (0.05 sec)  

建立可抛出一個異常的函數

php mysql事務詳解

<?php   

//建立可抛出一個異常的函數  

function checknum($number){  

    if($number>1){  

        throw new sqlexception("value must be 1 or below");  

    }  

    return true;  

//在 "try" 代碼塊中觸發異常  

try{  

    checknum(2);  

    //如果異常被抛出,那麼下面一行代碼将不會被輸出  

    echo 'if you see this, the number is 1 or below';  

}catch(exception $e){  

    //捕獲異常  

    echo 'message: ' .$e->getmessage();  

}catch(sqlexception $e){  

class sqlexception extends exception{}  

?>