PHP-PDO介紹

1.2 PDO介紹

1.2.1 連接數據庫方式

方法一:mysql擴展【這種方式php7已經淘汰】
方法二:mysqli擴展
方法三:PDO擴展

1.2.2 PDO介紹

PDO(PHP Data Object)擴展爲PHP訪問各種數據庫提供了一個輕量級,一致性的接口。無論訪問什麼數據庫,都可以通過一致性的接口去操作。

在這裏插入圖片描述

1.2.3 開啓PDO擴展

開啓PDO連接MySQL擴展

extension=php_pdo_mysql.dll

1.3 PDO核心類

1、PDO類:表示PHP和數據庫之間的一個連接
2、PDOStatement 類
​ 第一:表示執行數據查詢語句(select ,show)後的相關結果集
​ 第二:預處理對象
3、PDOException類:表示PDO的異常

在這裏插入圖片描述

1.4 實例化PDO對象

語法

__construct($dsn,用戶名,密碼)

1.4.1 DSN

DSN:data source name,數據源名稱,包含的是連接數據庫的信息,格式如下:

$dsn=數據庫類型:host=主機地址;port=端口號;dbname=數據庫名稱;charset=字符集

數據庫類型:

MySQL數據庫	=>	mysql:
oracle數據庫	=>	oci:
SQL Server 		=>sqlsrv:
具體驅動類型參見手冊“PDO驅動”

1.4.2 實例化PDO

實例化PDO的過程就是連接數據庫的過程

<?php
$dsn='mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo=new PDO($dsn,'root','root');
var_dump($pdo); //object(PDO)#1 (0) { } 

1.4.3 注意事項

1、如果連接的是本地數據庫,host可以省略

<?php
$dsn='mysql:port=3306;dbname=data;charset=utf8';
$pdo=new PDO($dsn,'root','root');
var_dump($pdo); //object(PDO)#1 (0) { } 

2、如果使用的是3306端口,port可以省略

<?php
$dsn='mysql:dbname=data;charset=utf8';
$pdo=new PDO($dsn,'root','root');
var_dump($pdo); //object(PDO)#1 (0) { } 

3、charset也省略,如果省略,使用的是默認字符編碼

<?php
$dsn='mysql:dbname=data';
$pdo=new PDO($dsn,'root','root');
var_dump($pdo); 

4、dbname也可以省略,如果省略就沒有選擇數據庫

<?php
$dsn='mysql:';
$pdo=new PDO($dsn,'root','root');
var_dump($pdo); 

5、host、port、dbname、charset不區分大小寫,沒有先後順序

6、驅動名稱不能省略,冒號不能省略(因爲冒號是驅動名組成部分),數據庫驅動只能小寫

1.5 使用PDO

1.5.1 執行數據操作語句

方法:pdo>exec(pdo->exec(sql),執行數據增、刪、改語句,執行成功返回受影響的記錄數,如果SQL語句錯誤返回false。

<?php
//1、實例化PDO
$dsn='mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo=new PDO($dsn,'root','root');
//2執行數據操作語句
//2.1 執行增加
/*
if($pdo->exec("insert into news values (null,'bb','bbbbbb',unix_timestamp())"))
    echo '自動增長的編號是:'.$pdo->lastInsertId (),'<br>';
*/
//2.2 執行修改
//echo $pdo->exec("update news set title='靜夜思' where id in (3,4)");
//2.3 執行刪除
//echo $pdo->exec('delete from news where id=5');\
//2.4 完善
$sql="update news set title='靜夜思1' where ids in (3,4)";
$rs=$pdo->exec($sql);
if($rs){
    echo 'SQL語句執行成功<br>';
    if(substr($sql, 0,6)=='insert')
        echo '自動增長的編號是:'.$pdo->lastInsertId (),'<br>';
    else
        echo '受到影響的記錄數是:'.$rs,'<br>';
}elseif($rs===0){
    echo '數據沒有變化<br>';
}elseif($rs===false){
    echo 'SQL語句執行失敗<br>';
    echo '錯誤編號:'.$pdo->errorCode(),'<br>';
    //var_dump($pdo->errorInfo());
    echo '錯誤信息:'.$pdo->errorInfo()[2];
}

1.5.2 執行數據查詢語句

方法:pdo>query(pdo->query(sql),返回的是PDOStatement對象

<?php
$dsn='mysql:dbname=data;charset=utf8';
$pdo=new PDO($dsn,'root','root');
//1、執行數據查詢語句
$stmt=$pdo->query('select * from products');
//var_dump($stmt);        //object(PDOStatement)
//2、獲取數據
//2.1  獲取二維數組
//$rs=$stmt->fetchAll();  //默認返回關聯和索引數組
//$rs=$stmt->fetchAll(PDO::FETCH_BOTH);     //返回關聯和索引數組
//$rs=$stmt->fetchAll(PDO::FETCH_NUM);      //返回索引數組
//$rs=$stmt->fetchAll(PDO::FETCH_ASSOC);    //返回關聯數組
//$rs=$stmt->fetchAll(PDO::FETCH_OBJ);        //返回對象數組

//2.2  獲取一維數組,匹配完成後指針下移一條
//$rs=$stmt->fetch();     //關聯和索引數組
//$rs=$stmt->fetch(PDO::FETCH_NUM);   //索引數組
//例題:通過while循環獲取所有數據
/*
while($row=$stmt->fetch(PDO::FETCH_ASSOC)){
    $rs[]=$row;
}
echo '<pre>';
var_dump($rs);
 */

//3.3  匹配列:匹配當前行的第n列,列的編號從0開始,匹配完畢後指針下移一條
//echo $stmt->fetchColumn();  //獲取當前行的第0列
//echo $stmt->fetchColumn(1);  //獲取當前行的第1列

//3.4  總行數,總列數
/*
echo '總行數:'.$stmt->rowCount(),'<br>';
echo '總列數:'.$stmt->columnCount();
*/

//3.5 遍歷PDOStatement對象(PDOStatement對象是有迭代器的)
foreach($stmt as $row){
    echo $row['proname'],'-',$row['proprice'],'<br>';
}
stdClass類是所有PHP類的父類

1.5.3 PDO操作事務

事務:是一個整體,要麼一起執行,要麼一起回滾

事務的特性:原子性,一致性,隔離性,永久性

需要將多個SQL語句作爲一個整體執行,就需要使用到事務

語法

start transaction 或 begin		開啓事務
commit	提交事務
rollback	回滾事務

例題

創建測試數據

create table bank(
       cardid char(4) primary key comment '卡號',
       balance decimal(10,2) not null comment '餘額'
)engine=innodb charset=utf8 comment '銀行卡號表'

insert into bank values ('1001',1000),('1002',1)

PDO操作事務

<body>
<?php
if(!empty($_POST)){
    $dsn='mysql:dbname=data;charset=utf8';
    $pdo=new PDO($dsn,'root','root');
    $out=$_POST['card_out'];    //轉出卡號
    $in=$_POST['card_in'];      //注入卡號
    $money=$_POST['money'];     //金額
    $pdo->beginTransaction();   //開啓事務
    //轉賬
    $flag1=$pdo->exec("update bank set balance=balance-$money where cardid='$out'");
    $flag2=$pdo->exec("update bank set balance=balance+$money where cardid='$in'");
    //查看轉出的賬號是否大於0,大於0返回true,否則返回false
    $stmt=$pdo->query("select balance from bank where cardid='$out'"); 
    $flag3=$stmt->fetchColumn()>=0?1:0;
    
    if($flag1 && $flag2 && $flag3){
        $pdo->commit ();    //提交事務
        echo '轉賬成功';
    }
    else{
        $pdo->rollBack ();  //回滾事務
        echo '轉賬失敗';
    }
}
?>
<form action="" method="post">
    轉出卡號: <input type="text" name="card_out" id=""> <br>
    轉入卡號: <input type="text" name="card_in" id=""> <br>
    金額:<input type="text" name="money" id=""> <br>
    <input type="submit" value="提交">
</form>
</body>

運行結果

在這裏插入圖片描述

小結:

 $pdo->beginTransaction()	開啓事務
 $pdo->commit ()			提交事務
 $pdo->rollBack()			回滾事務

1.5.4 PDO操作預處理

複習MySQL中預處理

預處理好處:編譯一次多次執行,用來解決一條SQL語句多次執行的問題,提高了執行效率。

預處理語句:

prepare 預處理名字 from 'sql語句'

執行預處理

execute 預處理名字 [using 變量]

PDO中的預處理——位置佔位符

<?php
    $dsn='mysql:dbname=data;charset=utf8';
    $pdo=new PDO($dsn,'root','root');
    //創建預處理對象
    $stmt=$pdo->prepare("insert into bank values (?,?)");   //?是佔位符
    //執行預處理
    $cards=[
        ['1003',500],
        ['1004',100]
    ];
    foreach($cards as $card){
        //綁定參數,並執行預處理,
        //方法一:
        /*
        $stmt->bindParam(1, $card[0]);  //佔位符的位置從1開始
        $stmt->bindParam(2, $card[1]);
        $stmt->execute();               //執行預處理
         */
        //方法二:
        /*
        $stmt->bindValue(1, $card[0]);
        $stmt->bindValue(2, $card[1]);
        $stmt->execute();
         */
        //方法三:如果佔位符的順序和數組的順序一致,可以直接傳遞數組
        $stmt->execute($card);  
    }

PDO中的預處理——參數佔位符

<?php
$dsn='mysql:dbname=data;charset=utf8';
$pdo=new PDO($dsn,'root','root');
//創建預處理對象
$stmt=$pdo->prepare("insert into bank values (:p1,:p2)");   //:p1,:p2是參數佔位符
//執行預處理
$cards=[
    ['p1'=>'1003','p2'=>500],
    ['p1'=>'1004','p2'=>1000]
];
foreach($cards as $card){
    //方法一:
    /*
    $stmt->bindParam(':p1', $card['p1']);
    $stmt->bindParam(':p2', $card['p2']);
    $stmt->execute();
     */
    //方法二:但數組的下標和參數名一致的時候就可以直接傳遞關聯數組
    $stmt->execute($card);
}

小結:

1、?是位置佔位符

2、參數佔位符以冒號開頭

3、stmt>bindParam()stmt->bindParam()和stmt->bindValue()區別

在這裏插入圖片描述

4、預處理的好處

a)提高執行效率
b)提高安全性

1.6 PDO異常處理

<?php
try{
    $dsn='mysql:dbname=data;charset=utf8';
    $pdo=new PDO($dsn,'root','root');
    //這是PDO錯誤模式屬性,PDO自動拋出異常
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->query('select * from newsssssss');  //自動拋出異常
} catch (PDOException $ex) {
    echo '錯誤信息:'.$ex->getMessage(),'<br>';
    echo '錯誤文件:'.$ex->getFile(),'<br>';
    echo '錯誤行號:'.$ex->getLine();
}

小結:

1、PDOException是PDO的異常類

2、實例化PDO會自動拋出異常

3、其他操作不會拋出異常,需要設置PDO的異常模式

4、PDO異常模式

PDO::ERRMODE_EXCEPTION	拋出異常
PDO::ERRMODE_SILENT		中斷
PDO::ERRMODE_WARNING	警告

1.7 單例模式封裝MyPDO類

1.7.1 步驟

1、單例模式

2、初始化參數

3、連接數據庫

4、執行增刪改

5、執行查詢

​ a)返回二維數組

​ b)返回一維數組

​ c)返回一行一列

1.7.2 代碼實現

第一部分:單例、初始化參數、實例化PDO

<?php
class MyPDO{
    private $type;      //數據庫類別
    private $host;      //主機地址
    private $port;      //端口號
    private $dbname;    //數據庫名
    private $charset;   //字符集
    private $user;      //用戶名
    private $pwd;       //密碼
    private $pdo;       //保存PDO對象
    private static $instance;
    private function __construct($param) {
        $this->initParam($param);
        $this->initPDO();
    }
    private function __clone() {
    }
    public static function getInstance($param=array()){
        if(!self::$instance instanceof self)
            self::$instance=new self($param);
        return self::$instance;
    }
    //初始化參數
    private function initParam($param){
        $this->type=$param['type']??'mysql';
        $this->host=$param['host']??'127.0.0.1';
        $this->port=$param['port']??'3306';
        $this->dbname=$param['dbname']??'data';
        $this->charset=$param['charset']??'utf8';
        $this->user=$param['user']??'root';
        $this->pwd=$param['pwd']??'root';
    }
    //初始化PDO
    private function initPDO(){
        try{
            $dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}";
            $this->pdo=new PDO($dsn, $this->user, $this->pwd);
        } catch (PDOException $ex) {
            echo '錯誤編號:'.$ex->getCode(),'<br>';
            echo '錯誤行號:'.$ex->getLine(),'<br>';
            echo '錯誤文件:'.$ex->getFile(),'<br>';
            echo '錯誤信息:'.$ex->getMessage(),'<br>';
            exit;
        }
    }
}
//測試
$param=array(
);
$mypdo= MyPDO::getInstance($param);
var_dump($mypdo);

第二部分:數據操作部分

<?php
class MyPDO{
    private $type;      //數據庫類別
    private $host;      //主機地址
    private $port;      //端口號
    private $dbname;    //數據庫名
    private $charset;   //字符集
    private $user;      //用戶名
    private $pwd;       //密碼
    private $pdo;       //保存PDO對象
    private static $instance;
    private function __construct($param) {
        $this->initParam($param);
        $this->initPDO();
        $this->initException();
    }
    private function __clone() {
    }
    public static function getInstance($param=array()){
        if(!self::$instance instanceof self)
            self::$instance=new self($param);
        return self::$instance;
    }
    //初始化參數
    private function initParam($param){
        $this->type=$param['type']??'mysql';
        $this->host=$param['host']??'127.0.0.1';
        $this->port=$param['port']??'3306';
        $this->dbname=$param['dbname']??'data';
        $this->charset=$param['charset']??'utf8';
        $this->user=$param['user']??'root';
        $this->pwd=$param['pwd']??'root';
    }
    //初始化PDO
    private function initPDO(){
        try{
            $dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}";
            $this->pdo=new PDO($dsn, $this->user, $this->pwd);
        } catch (PDOException $ex) {
            $this->showException($ex);
            exit;
        }
    }
    
    //顯示異常
    private function showException($ex,$sql=''){
        if($sql!=''){
            echo 'SQL語句執行失敗<br>';
            echo '錯誤的SQL語句是:'.$sql,'<br>';
        }
        echo '錯誤編號:'.$ex->getCode(),'<br>';
        echo '錯誤行號:'.$ex->getLine(),'<br>';
        echo '錯誤文件:'.$ex->getFile(),'<br>';
        echo '錯誤信息:'.$ex->getMessage(),'<br>';
    }
    //設置異常模式
    private function initException(){
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    }

    //執行增、刪、改操作
    public function exec($sql){
        try{
            return $this->pdo->exec($sql);
        } catch (PDOException $ex) {
            $this->showException($ex, $sql);
            exit;
        }
    }
    //獲取自動增長的編號
    public function lastInsertId(){
        return $this->pdo->lastInsertId();
    }
}
//測試
$param=array(
   
);
$mypdo= MyPDO::getInstance($param);
//echo $mypdo->exec('delete from news where id=6');
if($mypdo->exec("insert into news values (null,'11','1111',unix_timestamp())"))
    echo '自動增長的編號是:'.$mypdo->lastInsertId ();

第三部分:數據查詢部分

<?php
class MyPDO{
   ...
    
    //判斷匹配的類型
    private function fetchType($type){
        switch ($type){
            case 'num':
                return PDO::FETCH_NUM;
            case 'both':
                return PDO::FETCH_BOTH;
            case 'obj':
                return PDO::FETCH_OBJ;
            default:
                 return PDO::FETCH_ASSOC;
        }
    }
    //獲取所有數據 ,返回二維數組
    public function fetchAll($sql,$type='assoc'){
        try{
            $stmt=$this->pdo->query($sql);  //獲取PDOStatement對象
            $type= $this->fetchType($type); //獲取匹配方法
            return $stmt->fetchAll($type);
        } catch (Exception $ex) {
            $this->showException($ex, $sql);
        }
    }
    //獲取一維數組
    public function fetchRow($sql,$type='assoc'){
        try{
            $stmt=$this->pdo->query($sql);  //獲取PDOStatement對象
            $type= $this->fetchType($type); //獲取匹配方法
            return $stmt->fetch($type);
        } catch (Exception $ex) {
            $this->showException($ex, $sql);
            exit;
        }
    }
    //返回一行一列
    public function fetchColumn($sql){
        try{
             $stmt=$this->pdo->query($sql);
            return $stmt->fetchColumn();
        } catch (Exception $ex) {
            $this->showException($ex, $sql);
            exit;
        }
        
    }
    
}
//測試
$param=array(
   
);
$mypdo= MyPDO::getInstance($param);
//echo $mypdo->exec('delete from news where id=6');
/*
if($mypdo->exec("insert into news values (null,'11','1111',unix_timestamp())"))
    echo '自動增長的編號是:'.$mypdo->lastInsertId ();
 */

//$list=$mypdo->fetchAll('select * from news');
//$list=$mypdo->fetchRow('select * from news where id=1');
$list=$mypdo->fetchColumn('select count(*) from news');
echo '<pre>';
var_dump($list);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章