PDO
PDO 简介
PDO(PHP Data Object)PHP 数据对象,可以对各种数据库进行操作。PHP 默认情况下不支持 PDO 扩展,需要在 php.ini 中开启 PDO 扩展
PDO 扩展为 PHP 访问数据库定义了一个轻量级,一致性的接口,无论访问什么数据库都可以通过这个一致性的接口进行操作。
PDO 可以连接的数据库种类
PDO 的核心类
PDO 类:表示 PHP 和数据库之间的一个连接
PDOStatement 类
第一:表示执行 SQL 语句后的相关结果
第二:表示一条预处理语句
PDOException 类:表示 PDO 的异常类
在帮助文档中位置如下:
实例化 PDO 对象
开启 PDO 扩展
语法
构造函数:__construct(dsn, 用户名, 密码)
dsn
data source name 数据源对象
数据库类型: host = 主机地址; port = 端口号; dbname = 数据库名; charset = 字符集
例题
脚下留心:
有默认值的参数都可以省略,没有写数据库表示连接上但是没有选择数据库。
数据库类型只能小写
使用 PDO 对象
PDO->exec():执行数据操作语句,成功返回受影响的记录数,失败返回 false。
PDO->query():执行数据查询语句,返回 PDOStatement 对象
PDO->lastInsertId():返回插入的最后一条记录的 id 编号
PDO-> errorCode():返回执行 SQL 语句错误的编码
PDO-> errorInfo():返回错误信息数组
PDO->beginTransaction():开启事务
PDO->commit():提交事务
PDO->rollback():回滚事务
例题:PDO->exec()
创建 stu 数据表
create table stu(
id int unsigned auto_increment primary key comment ‘学号’,
name varchar(20) not null comment ‘姓名’,
score tinyint unsigned comment ‘成绩’
)
执行数据操作语句
$dsn=’mysql:host=localhost;dbname=data;port=3306;charset=utf8′;
$pdo=new PDO($dsn,’root’,’root’); // 实例化 pdo 对象
//$sql=”insert into stu values (5,’tom’,88)”;
$sql=”update stu set name=’tony’where id=5″;
if($result=$pdo->exec($sql)){ // 成功返回受影响的记录数,失败返回 false
echo ‘SQL 语句执行成功 <br>’;
echo ‘受影响的记录数:’.$result,'<Br>’;
echo ‘最后的 id 编号是:’.$pdo->lastInsertId(),'<br>’;
}
elseif($result===0){
echo ‘没有数据变化 <br>’;
}
elseif($result===false){
echo ‘SQL 执行失败,语句有误 <br>’;
echo ‘错误编号:’.$pdo->errorCode(),'<br>’;
$error=$pdo->errorInfo(); // 获取错误信息
//var_dump($error);
echo ‘错误信息:’.$error[2];
}
例题:事务
事务是一个整体,要么一起执行,要么一起不执行。
回顾数据库中事务
开启事务: start transaction 或者 begin work 或 begin
提交事务:commit
回滚事务:rollback
— 创建数据表
drop table if exists bank;
create table bank(
cardid char(4) primary key comment ‘卡号’,
name varchar(10) not null comment ‘姓名’,
balance decimal(10,2) not null comment ‘余额’
)engine=innodb charset=utf8 comment ‘银行表’;
— 插入测试数据
insert into bank values (‘1001′,’tom’,1000),(‘1002′,’berry’,1)
— 使用事务
mysql> begin //
mysql> update bank set balance=balance-100 where cardid=’1001′;
-> update bank set balance=balance+100 where cardid=’1002’//
mysql> select * from bank //
+——–+——-+———+
| cardid | name | balance |
+——–+——-+———+
| 1001 | tom | 900.00 |
| 1002 | berry | 101.00 |
+——–+——-+———+
2 rows in set (0.00 sec)
mysql> rollback //
Query OK, 0 rows affected (0.00 sec)
mysql> select * from bank //
+——–+——-+———+
| cardid | name | balance |
+——–+——-+———+
| 1001 | tom | 1000.00 |
| 1002 | berry | 1.00 |
+——–+——-+———+
2 rows in set (0.00 sec)
例题:使用 PDO 操作事务
<?php
$dsn=’mysql:dbname=data’;
$pdo=new PDO($dsn,’root’,’root’);
$pdo->beginTransaction(); // 开启事务
$rs1=$pdo->exec(“update bank set balance=balance-100 where cardid=’1001′”);
$rs2=$pdo->exec(“update bank set balance=balance+100 where cardid=’1002′”);
if($rs1>0 && $rs2>0)
$pdo->commit (); // 提交事务
else
$pdo->rollBack (); // 回滚事务
例题:PDO->query()
使用 PDOStatement 对象
$stmt->fetch():将对象中的一条数据匹配成关联和索引数组
$stmt->fetchAll():将对象中的所有数据匹配成二维数组
$stmt->fetchColumn():匹配列
$stmt->rowCount():总行数
$stmt->columnCount():总列数
$stmt->fetchObject():获取一条数据,匹配成类的对象
$stmt->bindColumn():将列绑定到变量上
匹配一条数据($stmt->fetch())
$rows=$stmt->fetch(); // 默认匹配成关联索引数组
$rows=$stmt->fetch(PDO::FETCH_BOTH); // 同上
$rows=$stmt->fetch(PDO::FETCH_ASSOC); // 匹配成关联数组
$rows=$stmt->fetch(PDO::FETCH_NUM); // 匹配成索引数组
$rows=$stmt->fetch(PDO::FETCH_OBJ); // 匹配成对象
匹配所有记录($stmt->fetchAll())
//$rs=$stmt->fetchAll();
//$rs=$stmt->fetchAll(PDO::FETCH_BOTH);
//$rs=$stmt->fetchAll(PDO::FETCH_ASSOC);
//$rs=$stmt->fetchAll(PDO::FETCH_BOTH);
//$rs=$stmt->fetchAll(PDO::FETCH_NUM);
//$rs=$stmt->fetchAll(PDO::FETCH_OBJ);
匹配列($stmt->fetchColumn())
//echo $stmt->fetchColumn(); // 默认是第一行的第 0 列
echo $stmt->fetchColumn(1); // 当前行的第 1 列,索引从 0 开始
获取总行数、总列数
echo ‘总行数:’.$stmt->rowCount().'<br>’;
echo ‘总列数:’.$stmt->columnCount(),'<br>’;
获取一条数据并匹配成指定类的对象
//$obj=$stmt->fetchObject(); // 不指定类,默认匹配成 stdClass 类
//$obj=$stmt->fetchObject(‘Student’); // 将数据匹配成 Student 类的属性
将列的数据绑定到变量上
$stmt->bindColumn(1, $id); // 将第 1 列绑定到 $id 变量上
$stmt->bindColumn(2, $name);// 将第 2 列绑定到 $name 变量上
$stmt->fetch();
echo $id,’-‘,$name,'<br>’; //1-tom
$stmt->bindColumn(‘id’, $id); // 将 id 字段绑定到 $id 变量上
$stmt->bindColumn(‘score’, $score); // 将 score 字段绑定到 $score 变量上
$stmt->fetch();
echo $id,’-‘,$score,'<br>’; //2-99
通过循环获取全部数据
while($rows=$stmt->fetch(PDO::FETCH_ASSOC)){
echo $rows[‘id’],’-‘,$rows[‘name’],’-‘,$rows[‘score’],'<br>’;
}
通过迭代获取全部数据
foreach($stmt as $rows){
echo $rows[‘id’],’-‘,$rows[‘name’],’-‘,$rows[‘score’],'<br>’;
}
全部代码
<?php
header(‘Content-Type:text/html;charset=utf-8′);
$dsn=’mysql:dbname=data’;
$pdo=new PDO($dsn,’root’,’root’);
$stmt=$pdo->query(‘select * from stu’); // 返回 PDOStatement 对象
/********** 第一个操作:匹配一条数据 *********/
/*
$rows=$stmt->fetch(); // 默认匹配成关联索引数组
$rows=$stmt->fetch(PDO::FETCH_BOTH); // 同上
$rows=$stmt->fetch(PDO::FETCH_ASSOC); // 匹配成关联数组
$rows=$stmt->fetch(PDO::FETCH_NUM); // 匹配成索引数组
$rows=$stmt->fetch(PDO::FETCH_OBJ); // 匹配成对象
*
*/
/********** 第二个操作:匹配所有记录 *********/
//$rs=$stmt->fetchAll();
//$rs=$stmt->fetchAll(PDO::FETCH_BOTH);
//$rs=$stmt->fetchAll(PDO::FETCH_ASSOC);
//$rs=$stmt->fetchAll(PDO::FETCH_BOTH);
//$rs=$stmt->fetchAll(PDO::FETCH_NUM);
//$rs=$stmt->fetchAll(PDO::FETCH_OBJ);
/********** 第三个操作:匹配列 *********/
//echo $stmt->fetchColumn(); // 默认是第一行的第 0 列
//echo $stmt->fetchColumn(1); // 当前行的第 1 列,索引从 0 开始
/********** 第四个操作:获取总行数,总列数 *********/
//echo ‘总行数:’.$stmt->rowCount().'<br>’;
//echo ‘总列数:’.$stmt->columnCount(),'<br>’;
/********** 第五个操作:获取一条数据并匹配成指定类的对象 *********/
class Student{
}
//$obj=$stmt->fetchObject(); // 不指定类,默认匹配成 stdClass 类
//$obj=$stmt->fetchObject(‘Student’); // 将数据匹配成 Student 类的属性
/********** 第六个操作:将列绑定到变量上 *********/
/*
$stmt->bindColumn(1, $id); // 将第 1 列绑定到 $id 变量上
$stmt->bindColumn(2, $name);// 将第 2 列绑定到 $name 变量上
$stmt->fetch();
echo $id,’-‘,$name,'<br>’; //1-tom
$stmt->bindColumn(‘id’, $id); // 将 id 字段绑定到 $id 变量上
$stmt->bindColumn(‘score’, $score); // 将 score 字段绑定到 $score 变量上
$stmt->fetch();
echo $id,’-‘,$score,'<br>’; //2-99
*
*/
/********** 第七个操作:循环所有数据 *********/
while($rows=$stmt->fetch(PDO::FETCH_ASSOC)){
echo $rows[‘id’],’-‘,$rows[‘name’],’-‘,$rows[‘score’],'<br>’;
}
/********** 第八个操作:通过迭代器遍历数据 *********/
foreach($stmt as $rows){
echo $rows[‘id’],’-‘,$rows[‘name’],’-‘,$rows[‘score’],'<br>’;
}
预处理语句
思考:为什么需要用到预处理?
答:如果有多个相同结构的 SQL 语句执行,都要会经历重复的以下过程:词法分析——语法分析——编译——执行, 我们可以使用预处理,编译一次,多次执行。提高执行效率。
MySQL 的预处理
声明预处理语句的语法:prepare 预处理名字 from ‘SQL 语句’
执行预处理语句:execute 预处理名字 [using 变量]
例题一(没有传递参数):
例题二(传递参数)
例题三(传递多个参数)
PDO 中的预处理
1、位置占位符
<?php
$dsn=’mysql:dbname=data’;
$pdo=new PDO($dsn,’root’,’root’);
$sql=’insert into stu values (null,?,?)’; //? 是位置占位符
$stmt=$pdo->prepare($sql); // 声明预处理语句,返回 PDOStatement 对象
$array=array(
array(‘aa’,10),
array(‘bb’,20),
array(‘cc’,30)
);
foreach($array as $a){
// 方法一
//$stmt->execute($a);
// 方法二:
/*
$stmt->bindValue(1, $a[0]); // 绑定数据
$stmt->bindValue(2, $a[1]);
$stmt->execute();
*/
// 方法三:
$stmt->bindParam(1, $a[0]); // 绑定数据
$stmt->bindParam(2, $a[1]);
$stmt->execute();
}
多学一招:bindValue() 和 bindParam() 的区别
bindValue() 可以将值或变量绑定到占位符上,bindParam() 只能将变量绑定到占位符上
2、参数占位符
<?php
$dsn=’mysql:dbname=data’;
$pdo=new PDO($dsn,’root’,’root’);
$sql=’insert into stu values (null,?,?)’; //? 是位置占位符
$stmt=$pdo->prepare($sql); // 声明预处理语句,返回 PDOStatement 对象
$array=array(
array(‘aa’,10),
array(‘bb’,20),
array(‘cc’,30)
);
$sql=’insert into stu values (null,:p1,:p2)’; // :p1,:p2 是参数占位符
$stmt=$pdo->prepare($sql); // 声明预处理语句
foreach($array as $a){
$stmt->bindParam(‘:p1’, $a[0]); // 编订参数
$stmt->bindParam(‘:p2’, $a[1]);
$stmt->execute();
}
预处理的好处
提高速度
提高安全性
PDO 属性操作
$pdo->getAttribute():获取 PDO 属性的值
$pdo->setAttribute():设置 PDO 属性
PDO 异常处理
单例模式实现 MyPDO 类的封装
<?php
class MyPDO{
private $type; // 数据库类型
private $host; // 主机地址
private $port; // 端口号
private $dbname; // 数据库名
private $charset; // 字符编码
private $user; // 用户名
private $pwd; // 密码
private $pdo; //PDO 对象
private static $instance; // 私有的静态属性保存 MyPDO 的单例
private function __construct($config) { // 私有的构造函数阻止在类的外部实例化对象
$this->initParam($config);
$this->initPDO();
$this->initException();
}
private function __clone(){ // 私有的__clone() 阻止在类的外部 clone 对象
}
public static function getInstance($config=array()){ // 公有的静态方法获取 MyPDO 的单例
if(!self::$instance instanceof self)
self::$instance=new self($config);
return self::$instance;
}
/*
* 初始化成员变量
* @param $config array 配置数组
*/
private function initParam($config){
$this->type=isset($config[‘type’])?$config[‘type’]:’mysql’;
$this->host=isset($config[‘host’])?$config[‘host’]:’127.0.0.1′;
$this->port=isset($config[‘port’])?$config[‘port’]:’3306′;
$this->dbname=isset($config[‘dbname’])?$config[‘dbname’]:”;
$this->charset=isset($config[‘charset’])?$config[‘charset’]:’utf8′;
$this->user=isset($config[‘user’])?$config[‘user’]:”;
$this->pwd=isset($config[‘pwd’])?$config[‘pwd’]:”;
}
/*
* 实例化 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 (Exception $e) {
$this->showException($e);
}
}
/*
* 设置自动抛出异常
*/
private function initException(){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}
/*
* 显示异常信息
* @param $e object 错误对象
* @parram $sql string 错误的 SQL 语句
*/
private function showException($e,$sql=”){
if($sql!=”)
echo “SQL 语句执行失败 <br> 错误的 SQL 语句是:{$sql}<br>”;
echo ‘错误信息:’.$e->getMessage(),'<br>’;
echo ‘错误编号:’.$e->getCode(),'<br>’;
echo ‘错误文件:’.$e->getFile(),'<br>’;
echo ‘错误行号:’.$e->getLine(),'<br>’;
exit;
}
/*
* 执行数据操作语句
* @return 成功返回受影响的记录数,失败返回 false
*/
public function exec($sql){
try
{
return $this->pdo->exec($sql);
}catch(PDOException $e){
$this->showException($e, $sql);
}
}
/*
* 返回插入数据的自动增长的编号
*/
public function lastInsertId(){
return $this->pdo->lastInsertId();
}
/*
* 获取 PDOStatement 对象
* @param $sql string SQL 语句
* @return PDOStatement 对象
*/
private function getPDOStatement($sql){
try
{
return $this->pdo->query($sql);
} catch (Exception $e) {
$this->showException($e);
}
}
/*
* 判断匹配类型
* @param $type string 用户需要的类型
* @return 常量
*/
private function getFetchType($type){
$allow=array(‘num’,’assoc’,’both’);
if(!in_array($type, $allow))
$type=’assoc’;
switch($type){
case ‘num’:
return PDO::FETCH_NUM;
case ‘assoc’:
return PDO::FETCH_ASSOC;
case ‘both’:
return PDO::FETCH_BOTH;
}
}
/*
* 获取一条记录
* @param $sql string SQL 语句
* @param $type string 匹配类型 num,assoc,both
* @return array 一维数组
*/
public function fetchRow($sql,$type=”){
$stmt= $this->getPDOStatement($sql);
$fetch_const= $this->getFetchType($type);
return $stmt->fetch($fetch_const);
}
/*
* 匹配所有数据
* @return array 二维数组
*/
public function fetchAll($sql,$type=”){
$stmt= $this->getPDOStatement($sql);
$fetch_const= $this->getFetchType($type);
return $stmt->fetchAll($fetch_const);
}
/*
* 获取遗憾一列的数据
*/
public function fetchColumn($sql){
try{
$stmt= $this->getPDOStatement($sql);
return $stmt->fetchColumn();
} catch (Exception $e) {
$this->showException($e);
}
}
}
header(‘Content-Type:text/html;charset=utf-8’);
// 测试
$config=array(
‘dbname’ => ‘data’,
‘user’ => ‘root’,
‘pwd’ => ‘root’
);
$mypdo= MyPDO::getInstance($config);
/*
if($mypdo->exec(“insert into stu values (null,’bb’,20)”))
echo $mypdo->lastInsertId ();
*/
/*
$rows=$mypdo->fetchAll(‘select * from stu order by id asc’,’num’);
echo ‘<pre>’;
print_r($rows);
*
*/
echo $mypdo->fetchColumn(‘select count(*) from stu’);