事務(transaction)及其acid屬性
事務是由一組sq語句組成的邏輯處理單元,事務具有以下4個屬性,通常簡稱為事務的acid屬性。
原子性(atomicity):事務是一個原子操作單元,其對資料的修改,要麼全都執行,要麼全都不執行。
持久性(durabe):事務完成之後,它對于資料的修改是永久性的,即使出現系統故障也能夠保持。
事物一般和異常處理結合
<?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到資料庫中。
//對于不支援事務的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。
比如下列語句
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
我們再來舉個例子看下。
$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不支援嵌套事務
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事物嵌套
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
//建立可抛出一個異常的函數
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{}
?>