數據庫抽象層 PDO 原

數據庫抽象層 PDO

鏈接與鏈接管理

如果有任何連接錯誤,將拋出一個 PDOException 異常對象。如果想處理錯誤狀態,可以捕獲異常,或者選擇留給通過 set_exception_handler() 設置的應用程序全局異常處理程序。

<?php
try {
    $dbh = new PDO('mysql:host=localhost;dbname=test',$user,$pass);
    foreach($dbh->query('select * from FOO') as $row){
        print_r($row);
    }
} catch(PDOException $e){
    print "ERROR!:".$e->getMessage()."<br/>";
    die();
}
?>

事務與自動提交

事務支持四大特性(ACID):原子性(Atomicity)、一致性(Consistency)隔離性(Isolation)以及持久性(Durability)

如果需要一個事務,則必須用 PDO::beginTransaction() 方法來啓動。如果底層驅動不支持事務,則拋出一個 PDOException 異常(不管錯誤處理設置是怎樣的,這都是一個嚴重的錯誤狀態)。一旦開始了事務,可用 PDO::commit()PDO::rollBack()來完成,這取決於事務中的代碼是否運行成功。

當腳本結束或連接即將被關閉時,如果尚有一個未完成的事務,那麼 PDO 將自動回滾該事務。這種安全措施有助於在腳本意外終止時避免出現不一致的情況——如果沒有顯式地提交事務,那麼假設是某個地方出錯了,所以執行回滾來保證數據安全。

Example #1 在事務中執行批處理

在下面例子中,假設爲新員工創建一組條目,分配一個爲23的ID。除了登記此人的基本數據之外,還需要記錄他的工資。兩個更新分別完成起來很簡單,但通過封閉在 PDO::beginTransaction()PDO::commit() 調用中,可以保證在更改完成之前,其他人無法看到這些更改。如果發生了錯誤,catch 塊回滾自事務啓動以來發生的所有更改,並輸出一條錯誤信息。

<?php
try{
    $dbh = new PDO('odbc:SAMPLE','db2inst1','ibmdb2',array(PDO::ATTR_PERSISTENT =>true));
    echo "Connected\n";
}catch(Exception $e){
    die("Unable to connect:".$e->getMessage());
}

try{
    $dbh -> setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    $bdh -> beginTransaction();
    $bdh -> exec("insert into staff (id,first,last) values(23,'JOE','Bloggs')");
    $bdh -> exec("insert into salarychange (id,amount,changedate) values (23,5000,Now())");
    $dbh -> commit();
}catch(Exception $e) {
    $dbh -> rollBack();
    echo "Failed:".$e -> getMeseeage();
}
?>

預處理語句與存儲過程

Example #1 用預處理語句進行重複插入

<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// 插入一行
$name = 'one';
$value = 1;
$stmt->execute();

//  用不同的值插入另一行
$name = 'two';
$value = 2;
$stmt->execute();
?>

Example #2 用預處理語句進行重複插入

下面例子通過用 name 和 value 取代 ? 佔位符的位置來執行一條插入查詢。

<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);

// 插入一行
$name = 'one';
$value = 1;
$stmt->execute();

// 用不同的值插入另一行
$name = 'two';
$value = 2;
$stmt->execute();
?>

Example #3 使用預處理語句獲取數據

下面例子獲取數據基於鍵值已提供的形式。用戶的輸入被自動用引號括起來,因此不會有 SQL 注入攻擊的危險。

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
}
?>

Example #6 佔位符的無效使用

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));

// 佔位符必須被用在整個值的位置
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>

錯誤與錯誤處理

PDO 提供了三種不同的錯誤處理模式,以滿足不同風格的應用開發:

  • PDO::ERRMODE_SILENT
  • PDO::ERRMODE_WARNING
  • PDO::ERRMODE_EXCEPTION

Example #1 創建 PDO 實例並設置錯誤模式

<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';

try {
    $dbh = new PDO($dsn, $user, $password);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}
?>

Note: 不管當前是否設置了 PDO::ATTR_ERRMODE ,如果連接失敗,PDO::__construct() 將總是拋出一個 PDOException 異常。未捕獲異常是致命的。 Example #2 創建 PDO 實例並在構造函數中設置錯誤模式

<?php
$dsn = 'mysql:dbname=test;host=127.0.0.1';
$user = 'googleguy';
$password = 'googleguy';

/*
    使用 try/catch 圍繞構造函數仍然有效,即使設置了 ERRMODE 爲 WARNING,
    因爲如果連接失敗,PDO::__construct 將總是拋出一個  PDOException 異常。
*/
try {
    $dbh = new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
    exit;
}

// 這裏將導致 PDO 拋出一個 E_WARNING 級別的錯誤,而不是 一個異常 (當數據表不存在時)
$dbh->query("SELECT wrongcolumn FROM wrongtable");
?>

以上例程會輸出:

Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.wrongtable' doesn't exist in /tmp/pdo_test.php on line 18

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章