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 執行數據操作語句
方法: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 執行數據查詢語句
方法: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->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);