翻译烂到家了,看不顺眼轻喷。。。 1.为什么要使用PDO? mysql_函数已经过时,相当一段时间以来,mysql_函数在其他SQL数据库编程接口方面已经有所差别;它不支持预处理,存储过程,事务等一些现代数据库设计思想,SQL语句字符串转义函数 mysql_real_escape_s

翻译烂到家了,看不顺眼轻喷。。。

1.为什么要使用PDO?

mysql_*函数已经过时,相当一段时间以来,mysql_*函数在其他SQL数据库编程接口方面已经有所差别;它不支持预处理,存储过程,事务等一些现代数据库设计思想,SQL语句字符串转义函数 mysql_real_escape_string() 和 拼接SQL语句的编程方法 已经过时并且很容易出错。最近一段时间里,它缺乏开发者的关注,缺少维护将可能导致一些安全问题不能被即时修复,或者在适配新版本的MySQL的时候不能正常工作,这成为mysql_*函数面临的的另一个问题。PHP社区最近也对mysql_*函数给出不建议使用的建议,也有可能在未来的版本中最终被弃用(不过不用过于担心,这可能还需要很长一段时间)。

PDO拥有更好的编程接口,你可以使用它写出更加简洁,高效,安全的代码。PDO还为不同的SQL数据库提供了不同的驱动,方便你使用新的数据库而不用再学习不同的编程接口。与拼接SQL语句构造查询语句不同,绑定参数可以简洁方便的构造出更加安全的查询语句,使用绑定参数的方法在 多次相似语句查询(仅仅某个参数不同)中也可以提高不少性能。PDO在错误处理方面也提供了多种方法。mysql_*函数缺乏一致的处理,与PDO的异常模式相比,或者说没有处理异常,使用PDO,你可以得到一致的错误处理,这将节省您大量的时间来跟踪问题。

在当前的PHP版本中,PDO模块是默认安装启用的,但是在使用PDO前你还需要安装另外两个软件包,一个是pdo_mysql数据库驱动程序,另外一个是类似php-mysql的mysql驱动程序。

2.连接MySQL

以前的方式:

$link = mysql_connect('localhost', 'user', 'pass');

mysql_select_db('testdb', $link);

mysql_set_charset('UTF-8', $link);

新的方式:

* 创建一个PDO对象,参数包括 DSN, username, password 和 一个驱动选项的数组(可忽略)。

* DSN其实就是一个告诉PDO该使用哪一种数据库驱动 和 一些连接信息的字符串,了解更多 PDO MYSQL DSN .

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

注意:确保DSN中设置了字符编码信息,否则将可能返回字符编码设置错误的信息,出于安全考虑,DSN最好包括字符编码信息设置。

你也可以在第四个参数数组里填写一些驱动选项,建议将 PDO异常模式(下文讲解) 和 关闭预处理模拟(默认打开的,仅对于旧版本MySQL有用)两个参数加入到第四个参数数组中。

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password', array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

你也可以在创建PDO对象后再通过setAttribute方法设置相应选项。

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

3.错误处理

mysql_*函数的错误处理

//connected to mysql

$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

OR die()是个不错的错误处理方法,但是会因此结束页面,将错误信息呈现到用户面前,这可能是我们不想看到的结果。

PDO有三种错误处理模式:

PDO::ERRMODE_SILENT # 和 mysql_*函数类似,检查代码并查看 $db->errorInfo(); 获取详细信息。

PDO::ERRMODE_WARNING # 抛出PHP警告。

PDO::ERRMODE_EXCEPTION #抛出 PDOException 异常,在我认为,这是我们应该使用的模式, 这和 die(mysql_error()); 类似,但是它可以捕获并抛出具体异常信息。

code:

try {

//connect as appropriate as above

$db->query('hi'); //invalid query!

} catch(PDOException $ex) {

echo "An Error occured!"; //user friendly message

some_logging_function($ex->getMessage());

}

注意:你可以不用立即执行并捕获异常,你可以在任何合适的时候随时捕获。

function getData($db) {

$stmt = $db->query("SELECT * FROM table");

return $stmt->fetchAll(PDO::FETCH_ASSOC);

}

//then much later

try {

getData($db);

} catch(PDOException $ex) {

//handle me.

}

如果你不想使用try/catch来处理异常,就像使用OR die()那样处理,在production模式下关闭display_errors选项即可。

4.简单的查询语句(SELECT)

mysql_*代码:

$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {

echo $row['field1'].' '.$row['field2']; //etc...

}

PDO代码:

foreach($db->query('SELECT * FROM table') as $row) {

echo $row['field1'].' '.$row['field2']; //etc...

}

query() 方法返回了一个 PDOStatement 对象,你可以通过如下方法获取结果:

$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {

echo $row['field1'].' '.$row['field2']; //etc...

}

或者

$stmt = $db->query('SELECT * FROM table');

$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//use $results

# Fetch Modes

注意 fetch() 和 fetchAll() 代码中的PDO::FETCH_ASSOC ,它高速 PDO 以关联数组的形式返回 键,值;其他比如PDO::FETCH_NUM模式,则返回数值键值的数组,默认模式是 PDO::FETCH_BOTH 则返回前面两者的集合,既有数值键值的数组,又有关联数组。PDO也可以获取数据返回对象PDO::FETCH_OBJ,PDO::FETCH_CLASS,PDO::FETCH_BOUND,bindColumn方法等更多内容,请阅读: PDOStatement Fetch documentation。

# 获取数据行数(Getting Row Count)

代替 mysql_num_rows 方法,你可以使用 PDOStatement对象的rowCount();方法。

$stmt = $db->query('SELECT * FROM table');

$row_count = $stmt->rowCount();

echo $row_count.' rows selected';

注意:官方文档称此函数仅适用于返回 `UPDATE`, `INSERT`, `DELETE`操作的`affected rows`,而 `SELECT`操作,仅对于`PDO_MYSQL` 驱动,此函数同样适用(谨记),在操作其他数据库的时候尤其注意。

# 获取最后操作ID(Getting the Last Insert Id)

mysql_*代码:

$result = mysql_query("INSERT INTO table(firstname, lastname) VALUES('John', 'Doe')") or die("Insert Failed ".mysql_error());

$insert_id = mysql_insert_id();

PDO代码:

$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");

$insertId = $db->lastInsertId();

5.执行 INSERT, UPDATE, DELETE 操作

mysql_*代码:

$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());

$affected_rows = mysql_affected_rows($result);

echo $affected_rows.' were affected';

PDO代码:

$affected_rows = $db->exec("UPDATE table SET field='value'");

echo $affected_rows.' were affected'

DELETE , INSERT 操作同样适用。

6.运行带有查询参数的语句(Running Statements With Parameters)

对于 不携带任何参数的查询语句,我们可以使用 query方法处理SELECT操作,使用exec方法处理 INSERT,UPDATE,INSERT操作,而对于携带查询参数的语句,你应该使用绑定参数的方法来安全的处理这些操作。

mysql_*代码:

$results = mysql_query(sprintf("SELECT * FROM table WHERE id='%s' AND name='%s'",

mysql_real_escape_string($id), mysql_real_escape_string($name))) or die(mysql_error());

$rows = array();

while($row = mysql_fetch_assoc($results)){

$rows[] = $row;

}

PDO代码:

$stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?");

$stmt->execute(array($id, $name));

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

prepare方法将查询语句发送到服务器,以“?”作为参数占位符进行编译,execute方法将查询参数发送到服务器,运行之前编译好的查询语句。因为 查询语句 和 查询参数 是分开发送的,所以在参数里的SQL语句是不可能被执行的,所以不会发生 SQL注入,这是一种比连接字符串构造SQL语句更加安全的解决方法。

注意:当你使用**绑定参数**的时候,不要对"?"占位符使用引号(SQL语句原来是对参数使用引号的),因为参数类型是在execute方法的时候确定的,所以在prepare的时候不必对占位符使用引号。

还有一些绑定参数的方法,bindValue方法可以分别绑定每个参数来代替execute方法的数组方式,同时还分别设置每个参数的类型。

$stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?");

$stmt->bindValue(1, $id, PDO::PARAM_INT);

$stmt->bindValue(2, $name, PDO::PARAM_STR);

$stmt->execute();

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

#命名占位符

如果你有许多参数需要绑定,不要使用问号占位符,以防混淆出错,你可以使用命名占位符代替问号占位符。

$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");

$stmt->bindValue(':id', $id, PDO::PARAM_INT);

$stmt->bindValue(':name', $name, PDO::PARAM_STR);

$stmt->execute();

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

你也可以使用execute方法,以数组的方式绑定参数:

$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");

$stmt->execute(array(':name' => $name, ':id' => $id));

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

#INSERT, DELETE, UPDATE 预处理查询

INSERT, DELETE, UPDATE 预处理语句的使用和SELECT类似,我们举几个例子:

$stmt = $db->prepare("INSERT INTO table(field1,field2,field3,field4,field5) VALUES(:field1,:field2,:field3,:field4,:field5)");

$stmt->execute(array(':field1' => $field1, ':field2' => $field2, ':field3' => $field3, ':field4' => $field4, ':field5' => $field5));

$affected_rows = $stmt->rowCount();

$stmt = $db->prepare("DELETE FROM table WHERE id=:id");

$stmt->bindValue(':id', $id, PDO::PARAM_STR);

$stmt->execute();

$affected_rows = $stmt->rowCount();

$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");

$stmt->execute(array($name, $id));

$affected_rows = $stmt->rowCount();

#在预处理中使用SQL函数

无效方法:

//THIS WILL NOT WORK!

$time = 'NOW()';

$name = 'BOB';

$stmt = $db->prepare("INSERT INTO table(`time`, `name`) VALUES(?, ?)");

$stmt->execute(array($time, $name));

正确方法

$name = 'BOB';

$stmt = $db->prepare("INSERT INTO table(`time`, `name`) VALUES(NOW(), ?)");

$stmt->execute(array($name));

你也可以在SQL函数里绑定参数:

$name = 'BOB';

$password = 'badpass';

$stmt = $db->prepare("INSERT INTO table(`hexvalue`, `password`) VALUES(HEX(?), PASSWORD(?))");

$stmt->execute(array($name, $password));

但是不能作为LIKE的参数:

//THIS DOES NOT WORK

$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE %?%");

$stmt->bindParam(1, $search, PDO::PARAM_STR);

$stmt->execute();

正确使用LIKE并绑定参数的方法:

$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?");

$stmt->bindValue(1, "%$search%", PDO::PARAM_STR);

$stmt->execute();

注意:这里使用的是bindValue而不是bindParam,否则会发生PDOException或致命错误。

#使用循环运行预处理语句

预处理语句可以一次设置,多次调用,因为仅在第一次传入的时候编译,因此在后来的多次调用中提高了不少效率。

典型的应用就是bindParam,bindParam与bindValue的不同之处在于,它不是绑定了参数的值,而是绑定参数变量本身,因此,如果参数变量变化了,那么在execute处理的时候,查询也将相应变化。

$values = array('bob', 'alice', 'lisa', 'john');

$name = '';

$stmt = $db->prepare("INSERT INTO table(`name`) VALUES(:name)");

$stmt->bindParam(':name', $name, PDO::PARAM_STR);

foreach($values as $name) {

$stmt->execute();

}

6.PDO中的事务(Transactions)

注意:调用beginTransaction()方法即自动关闭了自动提交。

try {

$db->beginTransaction();

$db->exec("SOME QUERY");

$stmt = $db->prepare("SOME OTHER QUERY?");

$stmt->execute(array($value));

$stmt = $db->prepare("YET ANOTHER QUERY??");

$stmt->execute(array($value2, $value3));

$db->commit();

} catch(PDOException $ex) {

//Something went wrong rollback!

$db->rollBack();

echo $ex->getMessage();

}

原文链接:PDO Tutorial for MySQL Developers

参考链接:PDO Documentation

延伸阅读:Validation and SQL Injection

php memcached mysql_PHP Memcached使用详解相关推荐

  1. Memcached原理深度分析详解

    Memcached是 danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能.关于这个东 西,相信很多人都用过,本文意在通 ...

  2. php memcached mysql_php memcached+Mysql(主从)

    /* index.php   程序入口,用来构造sql(如查询,更新) config.php  配置参数(memcache,mysql) init.php    封装memcached操作(memca ...

  3. Memcached Java Client API详解

    针对Memcached官方网站提供的java_memcached-release_2.0.1版本进行阅读分析,Memcached Java客户端lib库主要提供的调用类是SockIOPool和MemC ...

  4. 史上最强大型分布式架构详解:高并发+数据库+缓存+分布式+微服务+秒杀

    分布式架构设计是成长为架构师的必备技能,涵盖的内容很广,今天一次打包分享,文末有:最全分布式架构设计资料获取方式~ 负载均衡 负载均衡的原理和分类 负载均衡架构和应用场景 分布式缓存 常见分布式缓存比 ...

  5. 常用memcached命令详解

    常用memcached命令详解: Memcached作为缓存服务器,对其操作的命令主要分为三类: 1.  服务器状态命令:可以查看memcahced服务的当前状态 2.  数据存储命令:如何存储数据到 ...

  6. memcached使用详解

    memcached使用详解 一.memcached介绍 1.基于libevent的事件处理 libevent是一套跨平台的事件处理接口的封装,能够兼容包括这些操作系统:Windows/Linux/BS ...

  7. centos7 nginx php5.4,详解CentOS7.0下Nginx+PHP5.4+MySQL5.5+Memcached+Redis的架构部署

    详解Nginx+PHP5.4+MySQL5.5+Memcached+Redis的架构部署需要安装Nginx.PHP.mysql.memcached.redis! 一.硬件: 1.服务器型号:HP DL ...

  8. Memcached对象缓存详解

    一.NoSQL概述 NoSQL数据存储不需要固定的表结构,通常也不存在连接操作.在大数据存取上具备关系型数据库无法比拟的性能优势.随着互联网web2.0网站的兴起,NoSQL数据库现在成了一个极其热门 ...

  9. 详解从redis,memcached到nginx,网络底层io

    从redis,memcached到nginx,网络底层io的哪些事 1. redis的单线程模型 2. memcached的多线程模型 3. nginx的多进程模型 4. 10种网络模型的应用场景 视 ...

最新文章

  1. segMatch:基于3D点云分割的回环检测
  2. GCC 警告选项 -Werror
  3. infomix数据库版本sql_数据库周刊31丨华为openGauss 正式开源;7月数据库排行榜发布...
  4. mac vscode 实用快捷键
  5. Spring Roo 简介
  6. Xcode添加pch文件
  7. 『飞鸽』百度悄然进军客户端领域
  8. 【MySQL学习】-- 0x04 通配符小结
  9. 【转】Android将Activity打成jar包供第三方调用(解决资源文件不能打包的问题)...
  10. 189邮箱smpt服务器,189邮箱登录(常用邮箱客户端设置指南)
  11. WPF教程二:理解WPF的布局系统和常用的Panel布局
  12. shell脚本学习笔记(二)myplayer添加播放列表的源码
  13. 计算机方面的英语学术期刊,近几年计算机专业英文参考文献 计算机专业英文核心期刊参考文献有哪些...
  14. 软硬链接、引号符号、逻辑符号、系统通配符
  15. Permission denied (publickey).../RPC failed; curl 92 HTTP/2 stream 0 was.../pack exceeds maximum all
  16. 微带滤波器摘要_微带滤波器设计
  17. 制作精良、功能强大、毫秒精度、专业级的定时任务执行软件功能详解 —— 定时执行专家
  18. urllib2 爬虫 打印页面内容,部分无法显示
  19. 少儿编程培养孩子逻辑思维
  20. 前端将List列表转化为树型结构(reduce函数)

热门文章

  1. 转: MinGw离线安装方法集合
  2. java--杨辉三角
  3. myEclipse开发内存溢出解决办法myEclipse调整jvm内存大小java.lang.OutOfMemoryError: PermGen space及其解决方法...
  4. 46 关于Linux的I/O重定向
  5. Mac10.9 Mavericks 输入法切换快捷键
  6. WebKit 与 V8 的关系
  7. php 中文 decode_php json_decode 解析中文
  8. [Python图像处理] 三十三.图像各种特效处理及原理万字详解(毛玻璃、浮雕、素描、怀旧、流年、滤镜等)
  9. [系统安全] 四.OllyDbg动态分析工具基础用法及Crakeme逆向破解
  10. 【数据结构与算法】之深入解析“等差数列划分”的求解思路与算法示例