虽然所有主流数据库都遵循 SQL 标准,但程序员用来与数据库交互的接口却有很多不同。因此,应用程序几乎总是绑定与某个数据库,要求用户要么安装和维护所需的数据库, 要么选择一个与当前环境兼容,而不可以随便选择一款你想要的数据库。
比如,你使用不同的数据库,就必须使用不同的数据库扩展。MYSQL 有 mysql、mysqli 等,MSSQL 有 mssql,ORACLE 有 oracle 扩展,db2 有 db2 等。每个数据库都有自己的数 据库操作写法,如果一个系统已经采用了 MYSQL 数据库,突然要变更为 ORACLE,那么 数据库操作部分,就必须全部重写。
为了解决这个难题,企业程序员开始开发数据库抽象层,它能够解除应用程序逻辑与数 据库通信逻辑之间的耦合。通过这个通用接口传递所有与数据库相关的命令,应用程序就可 以使用多种数据库解决方案中的某一种了。
一.PDO 介绍
PDO 扩展为 PHP 访问数据库定义了一个轻量级的、一致性的接口,它提供了一个数据 访问抽象层,这样,无论使用什么数据库,都可以通过一致的函数执行查询和获取数据。 PDO 随 PHP5.1 发行,在 PHP5.0 的 PECL 扩展中也可以使用。
开启 PDO,如果是按照 Appserv 集成环境来开发的。系统会自动开启 PDO,我们可以 phpinfo 去查看一下。
extension=php_pdo.dll //开启 PDO extension=php_pdo_mysql.dll //PDO 访问 mysql 驱动
PDO 给开发者提供了三组类:PDO、PDOStatement、PDOException;分别为:数据库 使用、预处理、异常等操作。
PDO 还提供了大量的常量,以解决数据库操作的各种功能。
二.PDO数据库连接
如果是连接 mysql 数据库,可以使用一下方式:
$_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456');
在 PDO 构造方法里的三个参数分别为:数据源 DSN、用户名、密码
数据源 DSN:'数据库驱动:地址=localhost;数据库名=cms' 数据库驱动:mysql
对 PDO 错误的处理,有专门的 PDOException 异常类处理。
try { $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); }
PDO与连接有关的选项
可以使用$_pdo->getAttribute();来获取连接有关的选项,具体如下:
1.ATTR_AUTOCOMMIT 确定每次提交,是否等待 commit()方法才生效。
2.ATTR_CASE 强制获取的列字符大小写全部转换为大写或小写,或不动。有三个选项 可以控制:CASE_UPPER、CASE_LOWER 和 CASE_NATURAL。 3.ATTR_EMULATE_PREPARES 可使准备语句利用 MySQL 的查询缓存。
4.ATTR_ERRMODE 错误模式报告,PDO 支持三种:ERRMODE_EXCEPTION、 ERRMODE_SILENT 和 ERRMODE_WARNING。
5.ATTR_ORACLE_NULLS 设置为 TRUE 时,把字符串转成 NULL。默认情况 FALSE。
6.ATTR_PERSISTENT 是否持久连接。
7.ATTR_PREFETCH 预获取是一种获取多行的数据库特性。
8.ATTR_TIMEOUT 超时,MySQL 不支持。
9.ATTR_SERVER_INFO 数据库信息。
10.ATTR_SERVER_VERSION 数据库版本。
11.ATTR_CLIENT_VERSION 数据库客户端版本。
12.ATTR_CONNECTION_STATUS 数据库连接状态信息。
我们可以通过$_pdo->getAttribute();来获取这些属性信息,自然也可以通过 $_pdo->setAttribute();来设置它。
<?php try { $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } //设置自动提交 //$_pdo->setAttribute(PDO::ATTR_AUTOCOMMIT,false); //$_pdo->setAttribute(PDO::ATTR_SERVER_VERSION,'4.0'); //这个不行,不能修改 echo '是否自动提交:'.$_pdo->getAttribute(PDO::ATTR_AUTOCOMMIT).'<br />'; echo '数据库版本:'.$_pdo->getAttribute(PDO::ATTR_SERVER_VERSION); ?>
当然,还有一个更好的方法来设置,那就是 PDO 连接数据库的第四个参数:drive_opt。 通过数组来设置这些属性。
<?php try { $_drive_opt = array( PDO::ATTR_AUTOCOMMIT=>false ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); }
三.数据库操作
PDO 提供了几个执行查询的方法,每个方法都经过调整以尽可能更高效的方式执行一 个特定的查询。
1.执行没有结果集的查询:当执行 INSERT、UPDATE 和 DELETE 等查询时,不返回结 果集。在这些情况下,exec()方法将返回查询所影响的行数。
2.一次执行一个查询:当执行返回结果集的查询时,或者所影响的行数无关紧要时,应 当使用 query()方法。
3.多次执行一个查询:虽然可以使用 while 循环和 query()配合执行多次查询,但使用准 备语句来实现效率会更加高效 prepare()。
范例:使用 exec()新增一条数据
<?php try { $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456'); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "INSERT INTO cms_user (user,email) VALUES ('Zhou','zhou@163.com')"; $_pdo->exec($_sql); ?>
在 PDO 操作 SQL 如果有错误的情况下,他报错的方式提供了三种:
1.ERRMODE_EXCEPTION //异常模式,通过异常来捕获错误
2.ERRMODE_SILENT //默认模式,错误时不进行任何操作
3.ERRMODE_WARNING //警告模式,错误时会报警告
如果采用默认模式,那么,我们需要自行判断和输出错误结果。
<?php if (!$_affected_rows) { echo '错误代号:'.$_pdo->errorCode(); echo '<br />错误信息:'; print_r($_pdo->errorInfo()); }
如果设置了警告模式,会自动提醒PDO操作数据库存在的问题。
<?php try { $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456'); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "INSERT INTO cms_user (user,email) VALUES ('Zhou','zhou@163.com')"; $_pdo->exec($_sql); ?>
如果设置了异常模式,则需要通过 try{}catch{}来捕获。
<?php try { $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456'); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } try { $_sql = "INSERT INTO cms_user (use2r,email) VALUES ('Zhou','zhou@163.com')"; $_pdo->exec($_sql); } catch (PDOException $e) { echo 'SQL语句有误:'.$e->getMessage(); } ?>
使用 query()来设置字符集编码:
<?php try { $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456'); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); $_pdo->query('SET NAMES UTF8'); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); }
也可以是用常量来设置字符集编码:
<?php try { $_drive_opt = array( PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8' ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); }
使用 query()来获取数据集,要注意,获取后返回的不是结果集,而是预处理对象 PDOStatement。所以,可以通过 foreach 来循环获取。
<?php try { $_drive_opt = array( PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8' ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "SELECT user,pass FROM cms_user"; $_stmt = $_pdo->query($_sql); foreach ($_stmt as $_row) { print_r($_row); }
可以使用 query(sql,模式)方法中的第二个参数来确定数据的获取方式。
1.FETCH_BOTH 默认模式,关联和数字数组模式
2.FETCH_NUM 数字模式,数字数组模式
3.FETCH_ASSOC 关联模式,关联数组模式
4.FETCH_OBJ 对象模式,对象数组模式
<?php try { $_drive_opt = array( PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8' ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "SELECT user,pass FROM cms_user"; $_stmt = $_pdo->query($_sql,PDO::FETCH_OBJ); foreach ($_stmt as $_row) { print_r($_row); }
使用 fetch()方法,可以获取结果集下一行。我们也可以在 fetch(模式)里传入模式参数, 可以得到相应的数据获取方式。
<?php try { $_drive_opt = array( PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8' ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "SELECT user,pass FROM cms_user"; $_stmt = $_pdo->query($_sql); while (!!$_row = $_stmt->fetch()) { print_r($_row); }
使用 columnCount()方法返回结果集中的总列数。
echo $_stmt->columnCount();
使用 fetchAll()方法一次性获取所有数据。PS:大规模结果集会增加巨大的负担。
<?php try { $_drive_opt = array( PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8' ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "SELECT user,pass FROM cms_user"; $_stmt = $_pdo->query($_sql); foreach ($_stmt->fetchAll() as $_row) { print_r($_row); }
使用 fetchObject()方法以对象的方式获取下一行结果集。
<?php try { $_drive_opt = array( PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES UTF8' ); $_pdo = new PDO('mysql:host=localhost;dbname=cms','root','123456',$_drive_opt); $_pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING); } catch (PDOException $e) { exit('数据库链接错误:'.$e->getMessage()); } $_sql = "SELECT user,pass FROM cms_user"; $_stmt = $_pdo->query($_sql); while (!!$_row = $_stmt->fetchObject()) { print_r($_row); }
使用setFetchMode(模式),来统一指定结果集的获取方式。
$_stmt->setFetchMode();
使用 fetchColumn()方法返回结果集中下一行某个列的值。
echo $_stmt->fetchColumn(0);