PDO 的事务操作与预处理语句

2015-06-04 15:51:13   最后更新: 2015-06-04 16:43:45   访问数量:1671




事务支持四大特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability)

一个事务中执行的任何操作,即使是分阶段执行的,也能保证安全地应用于数据库,并在提交时不会受到来自其他连接的干扰

事务操作也可以根据请求自动撤销(假设还没有提交),这使得在脚本中处理错误更加容易

事务通常是通过把一批更改“积蓄”起来然后使之同时生效而实现的;这样做的好处是可以大大地提供这些更改的效率。换句话说,事务可以使脚本更快,而且可能更健壮(不过需要正确地使用事务才能获得这样的好处)

 

并不是每种数据库都支持事务,因此,默认情况下,PDO 在“自动提交”模式下工作,这意味着每条语句都有自己的隐式事务

需要调用 beginTransaction 方法切换到事务模式

无论错误处理方式是怎样的,如果底层驱动不支持事务,都会抛出一个 PDOException 异常

但只要数据库底层支持事务,则无论实际上事务是否可用,beginTransaction 都会返回 true,比如 mysql 数据库的 MyISAM 引擎并不支持事务,但 beginTransaction 依然会返回 true

 

在事务模式下,PDO 只有调用 commit 方法才会应用事务中的更改,而在更改完成前如果出现问题导致脚本退出,则事务内的所有操作会自动回滚

也可以使用 rollBack 方法主动回滚事务

 

可以通过调用 inTransaction 方法查看是否在一个事务中

 

<?php try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', array(PDO::ATTR_PERSISTENT => true)); echo "Connected\n"; } catch (Exception $e) { die("Unable to connect: " . $e->getMessage()); } try { $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->beginTransaction(); $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')"); $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())"); $dbh->commit(); } catch (Exception $e) { $dbh->rollBack(); echo "Failed: " . $e->getMessage(); } ?>

 

 

很多成熟的数据库支持预处理语句,类似于预编译模板,对预处理的 sql 语句通过不同的参数进行调用

 

  1. 查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析/编译/优化周期。简言之,预处理语句占用更少的资源,因而运行得更快。
  2. 提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生SQL 注入。(然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在 SQL 注入的风险)。

 

由于预处理语句在实际应用中非常有用,与事务不同,即使数据库并不支持预处理语句,PDO 也会通过模拟的方式实现这一特性

同时,由于参数会自动用引号括起来,所以不需要担心 sql 注入的问题

 

PDO 通过 prepare 使用一个预处理语句创建一个 PDOStatement 类对象

通过 PDOStatement 对象的 bindParam 方法绑定参数

也可以通过 PDOStatement 对象的 bindColumn 方法绑定列号

通过 PDOStatement 对象的 execute 方法应用整个存储过程

 

重复插入

<?php $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); $stmt->bindParam(':name', $name); $stmt->bindParam(':value', $value); // 插入一行 $name = 'one'; $value = 1; $stmt->execute(); // 用不同的值插入另一行 $name = 'two'; $value = 2; $stmt->execute(); ?>

 

 

通过序号绑定参数

<?php $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)"); $stmt->bindParam(1, $name); $stmt->bindParam(2, $value); // 插入一行 $name = 'one'; $value = 1; $stmt->execute(); // 用不同的值插入另一行 $name = 'two'; $value = 2; $stmt->execute(); ?>

 

 

selec 操作

<?php $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?"); if ($stmt->execute(array($_GET['name']))) { while ($row = $stmt->fetch()) { print_r($row); } } ?>

 

 

绑定列号

<?php function readData($dbh) { $sql = 'SELECT name, colour, calories FROM fruit'; try { $stmt = $dbh->prepare($sql); $stmt->execute(); /* 通过列号绑定 */ $stmt->bindColumn(1, $name); $stmt->bindColumn(2, $colour); /* 通过列名绑定 */ $stmt->bindColumn('calories', $cals); while ($row = $stmt->fetch(PDO::FETCH_BOUND)) { $data = $name . "\t" . $colour . "\t" . $cals . "\n"; print $data; } } catch (PDOException $e) { print $e->getMessage(); } } readData($dbh); ?>

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 






php      mysql      database      龙潭书斋      技术分享      数据库      transaction      数据      面向对象      oop      oo      pdo      object      orm      技术贴      事务      data      pdostatement      commit      rollback      execute      prepare     


京ICP备15018585号