PDO(php data object)
PDO为php访问数据库定义了一个轻量级的一致接口,只要某个数据库驱动实现了PDO接口,就可以把它的数据库特性作为PHP的标准扩展功能。但是PDO扩展本身并不实现任何数据库功能,它只是定义了一种接口格式,必须使用一个具体的数据库的PDO驱动来实现数据库的读写功能。因为PDO提供了一个数据访问抽象层,这表示,不管使用哪种数据库,只要这个数据库实现了PDO的接口,都可以用相同的方法拉力操作数据库。PDO不提供数据库的抽象层,它不会重写SQL。
安装配置
PDO安装不需要依赖其他扩展,php5.1.0以后,PDO和PDO_SQLITE默认可用,但是使用PDO访问自己选择的数据库,需要启用相应的PDO驱动。当作为一个共享模块安装PDO时,需要在php.ini里面加上extension=pdo.so配置,保证在php运行时pdo模块被自动加载,还要加上相应的数据库驱动,但是需要注意的是,PDO必须在具体的数据库扩展被载入之前初始化。
连接与连接管理
连接是通过实例化一个PDO 基类建立的。不管使用哪种数据库驱动,都是用 PDO 类名。构造函数接收用于指定数据库源(所谓的 DSN)或者用户名密码等参数,栗子:$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass),如果有任何连接错误,将抛出一个 PDOException 异常对象。
如果想处理错误状态,可以捕获异常,或者选择留给通过 set_exception_handler() 设置的应用程序全局异常处理程序。如果应用程序不在 PDO 构造函数中捕获异常,zend 引擎采取的处理方法是结束脚本并显示一个回溯跟踪,这个回溯跟踪可能泄漏完整的数据库连接细节,包括用户名和密码。因此最好显式(通过 catch 语句)或隐式(通过 set_exception_handler() )地捕获异常。
连接数据成功后,返回一个 PDO 类的实例给脚本,此连接在 PDO 对象的生存周期中保持活动。要想关闭连接,需要销毁对象,这样确保所有到它的引用都可以被删除,可以赋一个 NULL 值给对象。如果不这么做,PHP 在脚本结束时会自动关闭连接。
但是自PHP 5.4.26起,这种情况出现了意外:如果一个PDO对象只是被实例化,而没有执行任何查询操作,给PDO对象设置个NULL值并不能关闭连接,exec,query等查询函数执行会返回一个stmt对象,这个stmt对象会持有对数据库的引用,除非把这个stmt对象置为null,再把PDO对象置为null才会关闭连接。
很多WEB应用程序通过使用数据库的持久连接提高程序的性能,因为持久连接在脚本结束后不会被关闭,暂时被缓存,当另一个使用相同凭证的脚本发出连接数据库请求时就会复用这个连接,避免每次脚本需要与数据库会话时建立一个新的连接的开销。
如果想使用持久连接,必须在传递给 PDO 构造函数的驱动选项数组中设置 PDO::ATTR_PERSISTENT 。如果是在对象初始化之后用 PDO::setAttribute() 设置此属性,则驱动程序将不会使用持久连接。
事务与自动提交
事务支持四大特性(ACID)
原子性(Atomicity):一个事务要么全部执行要么全部不执行,不会存在执行一部分的情况。
一致性(Consistency):事务的运行不改变数据库操作中的数据一致性,栗子:完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变.
隔离性(Isolation):两个以上的事务不会出现交错执行的状态.因为这样可能会导致数据不一致.
持久性(Durability):事务执行成功以后,该事务所对数据库所作的更改便是持久的保存在数据库之中,不会无缘无故的回滚.
事务通常是通过把一批更改“积蓄”起来然后使之同时生效而实现的,这样做的好处是可以大大地提供这些更改的效率,因此事务可以使脚本更快。
PDO用 PDO::beginTransaction() 方法来启动事务,这个语句后面的所有sql不会被立刻执行,直到遇到PDO::commit() 函数。如果底层驱动不支持事务,则抛出一个 PDOException 异常,出现异常可以用PDO::rollBack()来回滚事务。
预处理语句与存储过程
预处理语句,就是把想要运行的 SQL 预先编译成一个模板,可以多次调用不停的参数来执行数据库的查询操作。栗子:
<pre>
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);//预处理sql参数
$stmt->bindParam(':value', $value);
// 第一次把name赋值one,插入
$name = 'one';
$value = 1;
$stmt->execute();
// 用不同的值插入另一行
$name = 'two';
$value = 2;
$stmt->execute();
</pre>
预处理的好处:
查询只需要一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。如果这个查询很复杂,这个过程要话费很长时间。通过使用预处理语句,可以避免重复分析/编译/优化周期。所以,预处理语句占用更少的资源,因而运行得更快。
提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生SQL 注入。但是,如果查询的其他部分是由未转义的输入来构建的,则仍存在 SQL 注入的风险。