PDO 使用
PDO扩展:
1、安装扩展 php_pdo.dll
2、安装驱动 php_pdo_mysql.dll
linux 编译时参数:--with-pdo=mysql=/usr/local/mysql
DSN表示:
data source name(数据源) 包括 主机、库名、驱动名
mysql:host=localhost;port=3307;dbname=testdb
mysql:unix_socket=/tmp/mysql.sock;dbname=testdb
PDO对象使用
1. 创建对象:
$dsn = "mysql:host=127.0.0.1;port=3306;dbname=test";
$opts = array(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_AUTOCOMMIT => 0 #关闭自动提交,
PDO::ATTR_TIMEOUT => 3 #设置超时时间
);
$pdo = new PDO($dsn, 'root', '', $opts);
// setAttribute 可以设置属性
$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);
// 设置获取的方式
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
异常处理常量:
- PDO::ERRMODE_SILENT(0): 默认 不提示任何错误
连接时无论如何都会提示,只有在执行后面的方法时才会起作用 - PDO::ERRMODE_WARNING(1 : 警告
- PDO::ERRMODE_EXCEPTION(2):异常(推荐使用)
用try catch捕获,也可以手动抛出异常 new PDOException($message, $code, $previous)
2. 执行sql语句 -- exec() 、query()、 perpare()
- query: 用来处理有结果集的,如select, 返回 PDOStatement 对象,失败返回false(当为 PDO::ERRMODE_SILENT,这也是默认的值)
- exec: 用来处理有返回影响行数的(int),如 insert(插入的行数)、 delete(删除的行数) 、update(和原数值不等才算), 失败返回false (当为 PDO::ERRMODE_SILENT,这也是默认的值)
- prepare: 执行所有sql,可以完全替代 query,exec的功能
exec用法:
//exec用法
try {
$sql = "INSERT INTO example(id, name, age) VALUES(1, 'xiaohong', 19)";
$rows = $pdo->exec($sql); //影响的条数 2
$pdo->lastInsertId(); //最后插入的id,有多条时返回的是第一条的id
} catch (Exception $e) {
ee($pdo->errorInfo());
}
query用法:
#query方法同样也可以执行insert,delete 只是返回的结果集的格式
#同样 lastInsertId 照样也可以使用
$statement = "INSERT INTO example(id, name, age) VALUES(2, 'xiaogang', 19)";
$flag = $pdo->query($statement);
var_dump($flag);
var_dump($pdo->lastInsertId());
#query可以实现所有exec的功能
$statement = "INSERT INTO example(id, name, age) VALUES(3, 'xiaoming', 19)";
$statement = "SELECT * FROM example";
$statement = "DELETE FROM example WHERE id = 1";
$statement = "UPDATE example set age=5 WHERE id = 1";
$stmt = $pdo->query($statement);
var_dump($stmt->rowCount());
总结:
- 1、query和exec都可以执行所有的sql语句,只是返回值不同而已。
- 2、query可以实现所有exec的功能。
- 3、当把select语句应用到 exec 时,总是返回 0
-
- 注意:批量插入时,依次插入当遇到错误时后面的插入失败,但是前面的会插入成功。
预处理语句(prepare):
# pdo中有两种占位符号
# ? 参数 --- 索引数组, 按索引顺序使用
# 名子参数 ----关联数组, 按名称使用,和顺序无关
//准备好了一条语句,并入到服务器端,也已经编译过来了,就差为它分配数据过来
//同样适用于更新操作
$stmt=$pdo->prepare("INSERT INTO example(`name`, `age`) VALUES(:name,:age)");
//绑定参数,引用方式传递
$stmt->bindParam(":name", $name);
$stmt->bindParam(":age", $age);
//所有SQL都可执行
// $stmt=$pdo->prepare("INSERT INTO example(`name`, `age`) VALUES(?, ?)");
//绑定参数,引用方式传递
// $stmt->bindParam(1, $name, PDO::PARAM_STR); #起始值为 1
// $stmt->bindParam(2, $age, PDO::PARAM_INT);
#变量放到 bindParam 前后都可
$name = "xiaoji";
$order = 30;
if($stmt->execute()){
echo "执行成功";
echo "最后插入的ID:".$pdo->lastInsertId();
}else{
echo "执行失败!";
}
支持执行时绑定:
#无序方式
$stmt=$pdo->prepare("INSERT INTO example(`name`, `age`) VALUES(:name,:age)");
$stmt->execute(array(":name"=>"xiaohuang", ":age"=>"13");
$stmt->execute(array(":name"=>"xiaomi", ":age"=>"23");
#有序方式
//所有SQL都可执行
$stmt=$pdo->prepare("INSERT INTO example(`name`, `age`) VALUES(?,?)");
$stmt->execute(array("xiaohuang", "13"));
$stmt->execute(array("xiaomi", "23"));
获取结果:
//获取结果
$stmt = $pdo->prepare("SELECT * FROM example where `age` = :age");
$stmt->execute(array(':age'=>8));
//设置获取的方式
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$data = array();
//方式1
//$data = $stmt->fetchAll();
//方式2
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$data[] = $row;
}
var_dump($data);
#所有的条数,select insert delete update
$rowCount = $stmt->rowCount();
var_dump($rowCount);
事务:
/*
*
* 事务处理
* 张三从李四那里买了一台 2000 元的电脑
* 从张三帐号中扣出 2000元
* 向李四账号中加入 2000元
* 从商品表中减少一台电脑
* MyIsAM InnoDB
*/
try{
$pdo->beginTransaction();
$price=500;
$sql="update zhanghao set price=price-{$price} where id=1";
$affected_rows=$pdo->exec($sql);
if(!$affected_rows){
throw new PDOException("张三转出失败");
}
$sql="update zhanghao set price=price+{$price} where id=3";
$affected_rows=$pdo->exec($sql);
#发现问题手动抛出异常
if(!$affected_rows) {
throw new PDOException("向李四转入失败");
}
echo "交易成功!";
$pdo->commit();
}catch(PDOException $e){
echo $e->getMessage();
$pdo->rollback(); //只要捕获异常则回滚
}
//不管执行成功还是失败最后都要在关闭自动提交
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
更好的获取条数:
# SQL_CALC_FOUND_ROWS 只要执行一次较耗时的复杂查询可以同时得到与不带limit同样的记录条数
$pdo->setAttribute(array(PDO::MYSQL_USE_BUFFERED_QUERY=>TRUE));
$rs = $pdo->query('SELECT SQL_CALC_FOUND_ROWS * FROM table LIMIT 5,15');
$rs1 = $pdo->query('SELECT FOUND_ROWS()');
$rowCount = (int) $rs1->fetchColumn();
/* 使用一个数组的值执行一条含有 IN 子句的预处理语句 */
$params = array(1, 21, 63, 171);
/* 创建一个填充了和params相同数量占位符的字符串 */
$place_holders = implode(',', array_fill(0, count($params), '?'));
/*
对于 $params 数组中的每个值,要预处理的语句包含足够的未命名占位符 。
语句被执行时, $params 数组中的值被绑定到预处理语句中的占位符。
这和使用 PDOStatement::bindParam() 不一样,因为它需要一个引用变量。
PDOStatement::execute() 仅作为通过值绑定的替代。
*/
$sth = $pdo->prepare("SELECT id, name FROM contacts WHERE id IN ($place_holders)");
$sth->execute($params);
$data = ['a'=>'foo','b'=>'bar'];
$keys = array_keys($data);
$fields = '`'.implode('`, `',$keys).'`';
$placeholder = substr(str_repeat('?,',count($keys),0,-1));
$pdo->prepare("INSERT INTO `baz`($fields) VALUES($placeholder)")->execute(array_values($data));