PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。实现 PDO 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 PDO 扩展自身并不能实现任何数据库功能;必须使用一个 具体数据库的 PDO 驱动 来访问数据库服务。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。只要重载响应的驱动,修改连接语句即可!
__construct(string $dsn [, string $username[, string $password……); //构造函数
dsn:数据源名称或叫做 DSN,包含了请求连接到数据库的信息
例:mysql连接:
<?php try { $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass); foreach($dbh->query('SELECT * from FOO') as $row) { print_r($row); } $dbh = null; } catch (PDOException $e) { //异常处理 print "Error!: " . $e->getMessage() . "<br/>"; die(); } ?>
事务与自动提交
事务支持四大特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability)。通俗地讲,在一个事务中执行的任何操作,即使是分阶段执行的,也能保证安全地应用于数据库,并在提交时不会受到来自其他连接的干扰。事务操作也可以根据请求自动撤销(假设还没有提交),这使得在脚本中处理错误更加容易。
事务通常是通过把一批更改"积蓄"起来然后使之同时生效而实现的;这样做的好处是可以大大地提供这些更改的效率。换句话说,事务可以使脚本更快,而且可能更健壮(不过需要正确地使用事务才能获得这样的好处)。
注:MySQL中必须创建表类型为type=InnoDB,才支持事务处理
过程:
1、关闭自动提交 PDO::ATTR_AUTOCOMMIT=>0
2、开启事务 $pdo->beginTransaction()
3、开启自动提交 setAttribute(PDO::ATTR_AUTOCOMMIT, 1)
<?php try{ $pdo=new PDO("mysql:host=localhost;dbname=phpdb", "root", "123456", array(PDO::ATTR_AUTOCOMMIT=>0)); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //设置异常 }catch(PDOException $e){ echo "数据库连接失败:".$e->getMessage(); exit; } //执行SQL语句 exec() query() prepare() //一是有结果集的query(), 执行select语句 //exec()用来执行有影响行数的,update, delete insert, other //exec()返回的是影响的行数 /* * * 事务处理 * * 张三从李四那里买了一台 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);
1、默认模式 PDO::ERRMODE_SILENT
PDO 将只简单地设置错误码,可使用 PDO::errorCode() 和 PDO::errorInfo() 方法来检查语句和数据库对象。如果错误是由于对语句对象的调用而产生的,那么可以调用那个对象的 PDOStatement::errorCode() 或 PDOStatement::errorInfo() 方法。如果错误是由于调用数据库对象而产生的,那么可以在数据库对象上调用上述两个方法。
2、警告模式 PDO::ERRMODE_WARNING
警告模式会产生一个PHP警告,并设置errrorCode属性。如果设置的是警告模式,那么除非明确地检查错误代码,否则程序将继续按照其方式进行。即如果只是想看看发生了什么问题且不中断应用程序的流程,那么此设置在调试/测试期间非常有用。
$pdo->setAttribute(PDO::ERRMODE, PDO::ERRMODE_WARNING);
3、异常模式(常用) PDO::ERRMODE_EXCEPTION
除设置错误码之外,PDO 还将抛出一个 PDOException 异常类并设置它的属性来反射错误码和错误信息。此设置在调试期间也非常有用,因为它会有效地放大脚本中产生错误的点,从而可以非常快速地指出代码中有问题的潜在区域(记住:如果异常导致脚本终止,则事务被自动回滚)。
异常模式另一个非常有用的是,相比传统 PHP 风格的警告,可以更清晰地构建自己的错误处理,而且比起静默模式和显式地检查每种数据库调用的返回值,异常模式需要的代码/嵌套更少。
<?php $dsn = 'mysql:dbname=testdb;host=127.0.0.1'; $user = 'dbuser'; $password = 'dbpass'; try { $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { echo 'Connection failed: ' . $e->getMessage(); } ?>
预处理语句 【两步:1、在服务器中准备好sql语句;2、绑定参数bindParam()】
好处:
-
预处理语句大大减少了分析时间,只做了一次查询(虽然语句多次执行)。
-
绑定参数减少了服务器带宽,你只需要发送查询的参数,而不是整个语句。
-
预处理语句针对SQL注入是非常有用的,因为参数值发送后使用不同的协议,保证了数据的合法性。
两种占位符
1、参数绑定
// 预处理 SQL 并绑定参数 $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (:firstname, :lastname, :email)"); $stmt->bindParam(':firstname', $firstname); $stmt->bindParam(':lastname', $lastname); $stmt->bindParam(':email', $email); // 插入行 $firstname = "John"; $lastname = "Doe"; $email = "john@example.com"; $stmt->execute();
可用数组方式传入参数:$stmt->execute(array(":price"=>99, ":name"=>"kkk1", ":num"=>"451", ":desn"=>"aaaaaa1"));
2、?参数绑定
// 预处理及绑定 $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"); $stmt->bind_param("sss", $firstname, $lastname, $email); //"sss" 参数列处理其余参数的数据类型。s 字符告诉数据库该参数为字符串。(i整型,b二进制,d浮点型)
注:此绑定方法也可用顺序绑定
$stmt->bindParam(1, $name, PDO::PARAM_STR);
$stmt->bindParam(3, $num, PDO::PARAM_INT);
$stmt->bindParam(4, $desn, PDO::PARAM_STR);
$stmt->bindParam(2, $p, PDO::PARAM_STR);
注:setFetchMode() //设置数据获取模式
<?php $sql = 'SELECT name, colour, calories FROM fruit'; try { $stmt = $dbh->query($sql); $result = $stmt->setFetchMode(PDO::FETCH_NUM); while ($row = $stmt->fetch()) { print $row[0] . " " . $row[1] . " " . $row[2] . " "; } } catch (PDOException $e) { print $e->getMessage(); } ?>