MySQL資料庫之PDO擴充套件
阿新 • • 發佈:2020-12-15
PDO概述
-
連線資料庫方式
- mysql擴充套件 (這種方式php7已經淘汰)
- mysqli擴充套件
- PDO擴充套件
-
PDO介紹
- PDO(PHP Data Object)擴充套件為PHP訪問各種資料庫提供了一個輕量級,一致性的介面
- 無論訪問什麼資料庫,都可以通過一致性的介面去操作
-
開啟PDO擴充套件
- 開啟PDO連線MySQL擴充套件
extension=php_pdo_mysql.dll
-
PDO核心類
PDO
表示PHP和資料庫之間的一個連線PDOStatement
- 表示執行資料查詢語句(select ,show)後的相關結果集
- 預處理物件
PDOException
例項化PDO物件
- 語法
__construct($dsn,使用者名稱,密碼)
DSN
-
概念
- DSN:data source name
- 資料來源名稱,包含的是連線資料庫的資訊
-
格式
$dsn=資料庫型別:host=主機地址;port=埠號;dbname=資料庫名稱;charset=字符集
-
資料庫型別
- MySQL資料庫 => mysql:
- oracle資料庫 => oci:
- SQL Server => sqlsrv:
例項化PDO
- 概念
- 例項化PDO的過程就是連線資料庫的過程
<?php $dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8'; $pdo= new PDO($dsn,'root',''); var_dump($pdo); ?>
引數省略
- 引數省略
- 如果連線的是本地資料庫,host可以省略
- 如果使用的是3306埠,port可以省略
- charset也省略,如果省略,使用的是預設字元編碼
- dbname也可以省略,如果省略就沒有選擇資料庫
- host、port、dbname、charset不區分大小寫,沒有先後順序
- 驅動名稱不能省略,冒號不能省略(因為冒號是驅動名組成部分),資料庫驅動只能小寫
<?php
$dsn='mysql:';
$pdo=new PDO($dsn,'root','');
var_dump($pdo);
?>
使用PDO
執行資料操作語句
- 語法
$pdo->exec($sql)
- 執行資料增、刪、改語句
- 執行成功返回受影響的記錄數
- 如果SQL語句錯誤返回false
執行增加
<?php
$dsn='mysql:host=localhost;port=3306;dbname=sel;charset=utf8';
$pdo=new PDO($dsn,'root','');
if($pdo->exec("insert into news values (null,'基本知識','第6章',unix_timestamp())")){
echo '自動增長的編號是:'.$pdo->lastInsertId(),'<br>';
}
?>
執行刪除
<?php
$dsn='mysql:host=localhost;port=3306;dbname=sel;charset=utf8';
$pdo=new PDO($dsn,'root','');
if($pdo->exec('delete from news where id=13')){
echo 'delete success ^_^';
}
?>
執行修改
<?php
$dsn='mysql:host=localhost;port=3306;dbname=sel;charset=utf8';
$pdo=new PDO($dsn,'root','');
if($pdo->exec("update news set title='準備知識' where id in (3,4)")){
echo 'update success ^_^';
}
?>
優化寫法
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=sel;charset=utf8';
$pdo= new PDO($dsn,'root','');
$sql= "update news set title='基本知識' where id 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>';
echo '錯誤資訊:'.$pdo->errorInfo()[2];
}
?>
執行資料查詢語句
-
語法
$pdo->query($sql)
- 返回的是PDOStatement物件
-
獲取二維陣列
$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);
返回物件陣列
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetchAll();
var_dump($rs);
?>
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetchAll(PDO::FETCH_BOTH);
var_dump($rs);
?>
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetchAll(PDO::FETCH_NUM);
var_dump($rs);
?>
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($rs);
?>
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetchAll(PDO::FETCH_OBJ);
var_dump($rs);
?>
- 獲取一維陣列
$rs=$stmt->fetch();
關聯和索引陣列$rs=$stmt->fetch(PDO::FETCH_NUM);
索引陣列$row=$stmt->fetch(PDO::FETCH_ASSOC)
關聯陣列
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetch();
var_dump($rs);
?>
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
$rs=$stmt->fetch(PDO::FETCH_NUM);
var_dump($rs);
?>
# 通過while迴圈獲取所有資料
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
while($row=$stmt->fetch(PDO::FETCH_ASSOC)){
$rs[]=$row;
}
var_dump($rs);
?>
- 匹配列
- 匹配當前行的第n列,列的編號從0開始,匹配完畢後指標下移一條
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
for($i=0; $i<$stmt->columnCount(); $i++){
echo $stmt->fetchColumn($i).'<br>';
}
?>
- 總行數與總列數
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
echo '總行數:'.$stmt->rowCount(),'<br>';
echo '總列數:'.$stmt->columnCount();
?>
- 遍歷PDOStatement物件
- PDOStatement物件是有迭代器的
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$stmt=$pdo->query('select * from products');
foreach($stmt as $row){
echo $row['proname'],'-',$row['proprice'],'<br>';
}
?>
PDO操作事務
-
概念
- 事務:是一個整體,要麼一起執行,要麼一起回滾
- 事務的特性:原子性,一致性,隔離性,永久性
- 需要將多個SQL語句作為一個整體執行,就需要使用到事務
-
MySQL 事務語法
start transaction
開啟事務begin
開啟事務commit
提交事務rollback
回滾事務
-
PDO 事務語法
$pdo->beginTransaction()
開啟事務$pdo->commit ()
提交事務$pdo->rollBack()
回滾事務
# 建立測試資料表
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=data;charset=utf8';
$pdo= new PDO($dsn,'root','');
$pdo->beginTransaction();
$flag0= $pdo->exec("delete from bank");
$flag1= $pdo->exec("drop table bank");
$flag2= $pdo->exec("create table bank(cardid char(4) primary key comment '卡號',balance decimal(10,2) not null comment '餘額')engine=innodb charset=utf8 comment '銀行卡號表'");
$flag3= $pdo->exec("insert into bank values ('1001',1000),('1002',1)");
if($flag2==0 && $flag3){
$pdo->commit();
echo '資料表建立成功!';
}else{
$pdo->rollBack();
echo '資料表建立失敗!';
}
?>
# PDO操作事務
<body>
<?php
if(!empty($_POST)){
$dsn='mysql:dbname=sel;charset=utf8';
$pdo=new PDO($dsn,'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操作預處理
-
MySQL中的預處理
- 預處理好處:編譯一次多次執行,用來解決一條SQL語句多次執行的問題,提高了執行效率
- 預處理語句
prepare 預處理名字 from 'sql語句'
- 執行預處理
execute 預處理名字 [using 變數]
-
PDO中的預處理
- 位置佔位符
insert into bank values (?,?)
- 引數佔位符
insert into bank values (:p1,:p2)
$stmt->bindParam()
和$stmt->bindValue()
的區別$stmt->bindParam()
中的值只能是變數$stmt->bindValue()
中的值能是變數也可以為值
- 預處理的好處
- 提高執行效率
- 提高安全性
- 位置佔位符
# 位置佔位符
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=sel;charset=utf8';
$pdo= new PDO($dsn,'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);
}
echo '資料處理完成';
?>
# 引數佔位符
<?php
$dsn= 'mysql:host=localhost;port=3306;dbname=sel;charset=utf8';
$pdo= new PDO($dsn,'root','');
//建立預處理物件
$stmt=$pdo->prepare("insert into bank values (:p1,:p2)"); //:p1,:p2是引數佔位符
//執行預處理
$cards=[
['p1'=>'1005','p2'=>500],
['p1'=>'1006','p2'=>1000]
];
foreach($cards as $card){
//方法一:
/*
$stmt->bindParam(':p1', $card['p1']);
$stmt->bindParam(':p2', $card['p2']);
$stmt->execute();
*/
//方法二:但陣列的下標和引數名一致的時候就可以直接傳遞關聯陣列
$stmt->execute($card);
}
echo '資料處理完成';
?>
PDO異常處理
- 概念
- PDOException是PDO的異常類
- 例項化PDO會自動丟擲異常
- 其他操作不會丟擲異常,需要設定PDO的異常模式
- PDO異常模式
PDO::ERRMODE_EXCEPTION
丟擲異常PDO::ERRMODE_SILENT
中斷PDO::ERRMODE_WARNING
警告
<?php
try{
$dsn='mysql:dbname=data;charset=utf8';
$pdo=new PDO($dsn,'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();
}
?>
單例模式封裝MySQL-PDO
- 分析
- 單例模式
- 初始化引數
- 連線資料庫
- 執行增刪改
- 執行查詢
- 返回二維陣列
- 返回一維陣列
- 返回一行一列
第一部分:單例、初始化引數、例項化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);
?>