当前位置: 首页 > 后端技术 > PHP

PDO

时间:2023-03-29 16:38:22 PHP

的使用请参考《PHP核心技术与最佳实践》1的5.1章节。PDO简介PHP对于每个数据库都有一个独立的模块和一组独立的函数。这样的结构和设计使得PHP很难兼容各种数据库。一旦将应用程序迁移到另一个数据库环境,或者需要添加新的数据库支持,就不得不重写与数据库相关的操作。通常写多个类,使用适配器模式来实现。PDO就是在这样的历史背景下应运而生的。PDO(PHPDataObjects)提供了访问各种数据库的通用接口,即抽象数据模型支持连接各种数据库。使用PDO,代码变得更简单、更安全。在PHP中,连接MySQL数据库通常有3种方式:MySQL系列函数:最常用的,过程式风格的一组应用(不推荐,PHP7.0已经废止)MySQLi系列函数:增强和改进MySQLfunctions版本,提供过程化和面向对象的API,增加预编译和参数绑定等新特性PDO:从句法上看,PDO更接近MySQLi。具体可以参考:【连接数据库】PHP7连接数据库的三种方法【原创】PDO相比MySQLi的优势在于支持多数据库,而MySQLi只能支持MySQL,所以一般推荐使用使用PDO操作数据库。PDO提供了一个数据访问抽象层,也就是说无论使用什么样的数据库,都可以使用同一套API来操作数据,保证了抽象和访问接口的一致性。启用PDO很容易。一般来说,PDO会在PHP安装后默认开启。如果没有,在php.ini中找到如下语句,去掉前面的分号;extension=php_pdo.dll第一步是配置数据源。后续使用和mysql扩容操作数据库的方法没有区别。PDO操作主要包括PDO::query()、PDO::exec()、PDO::prepare()PDO::query():主要用于返回记录结果的操作,尤其是SELECT操作PDO::exec():主要用于不返回结果集的操作,如INSERT、UPDATE、DELETE等,它返回的结果是当前操作影响的列数PDO::prepare():是主要是一个预处理操作,预处理中的SQL语句需要通过$rs->execute()来执行。该方法可以绑定参数,功能更强大。以下是PDO实例:setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);$db->e??xec("设置名称'UTF8'");//插入日志$sql="INSERTINTOusers(name,email,password,created_at)values('pdo_test','8888@qq.com','bbb',now())";$db->exec($sql);//使用预处理语句$insert=$db->prepare("INSERTINTOusers(name,email,password,created_at)values(?,?,?,now())");$插入->执行(数组('pdo_test1','8448657@qq.com','aaa'));//异常$insert->execute(array('pdo_test2','8448657@qq.com','aaa',9,10));$sql="selectname,email,password,created_atfromusers";$query=$db->准备($sql);$查询->执行();var_dump($query->fetchAll(PDO::FETCH_ASSOC));}catch(PDOException$e){echo$e->getMessage();}注意:使用PDO从MySQL数据库中查询到的数据都是字符串类型。在一些特殊的应用中,格式3可能需要转换。PDO的参数绑定和预编译PDO最大的特点就是引入了参数绑定和预编译。下面是从数据库中查询一条记录:query("SELECTnameFROMusersWHEREid=".$_GET['id']);这是糟糕的代码。将原始请求参数插入到SQL请求中。这将使黑客可以轻松地使用[SQL注入]进行攻击。想象一下,如果黑客通过http://domain.com/?id=1%3BDEL...之类的URL传递构造的id参数。这会将$_GET['id']变量的值设置为1;然后会执行DELETEFROMusers删除所有用户记录!因此,您应该使用PDO限制参数来过滤ID输入。上面的代码可以优化为:prepare('SELECTnameFROMusersWHEREid=:id');$id=filter_input(INPUT_GET,'id',FILTER_SANITIZE_NUMBER_INT);$stmt->bindParam(':id',$id,PDO::PARAM_INT);$stmt->execute();在MySQL应用中,为了防止Injection攻击,通常使用PHP中的intval、addslashes等函数对传入的参数进行转义,转换成SQL中合法的参数类型。这个方法比较复杂,但是使用PDO的bindParam方法会变得非常快。需要在函数中指定第三个参数对传入的参数进行转换,将其转换为需要的类型拼接成原始的SQL语句。例如:prepare('SELECTname,colour,caloriesFROMfruitWHEREcalories>:caloriesANDcolor=:colour');//绑定变量,将变量转换为int类型$sth->bindParam(':calories',$calories,PDO::PARAM_INT);//绑定变量,将变量转换为字符串类型$sth->bindParam(':colour',$colour,PDO::PARAM_STR,12);//执行$sth->execute();var_dump($sth->fetchAll(PDO::FETCH_ASSOC));//执行预处理语句(第二种绑定变量的方式)$sth=$db->prepare('SELECTname,colour,caloriesFROMfruitWHEREcalories>?ANDcolor=?');//绑定变量,将变量转换为int类型$sth->bindParam(1,$calories,PDO::PARAM_INT);//绑定变量,将变量转换为字符串类型$sth->bindParam(2,$colour,PDO::PARAM_STR,12);//执行$sth->execute();var_dump($sth->fetchAll(PDO::FETCH_ASSOC));预编译负责两件事,转义和软解析提速程序必须支持预编译,除了数据库支持,还需要驱动支持(PDO和MySQLi都支持)4.PDO事务处理一个事务中的所有工作都提交,即使它是分阶段执行的,也必须安全地应用于数据库,不受其他连接的干扰。当请求出现错误时,事务工作可以自动取消。事务的主要特性:原子性、一致性、独立性和持久性(Atomicity、Consistency、Isolation、Durability、ACID)。一个典型的应用是保存批量更改并立即执行,可以提高效率。一旦事务不成功,会回滚到初始状态,保证数据的一致性。SQL通常工作在auto-commit模式,即每条查询执行都有自己的隐式事务处理,无论数据库支持事务还是不存在因为数据库不支持事务,DML语句执行的结果都会立即生效并且不能改变。比如在MySQL中执行一条update语句,它的作用会立即生效,并且是永久不变的。在Oracle数据库中,默认是事务模式。如果要删除一条数据,数据不会被永久删除。只有执行commit命令后才会生效。PDO使用beginTransaction()方法创建事务。在事务中,使用commit()或rollback()方法结束事务,使用哪种方法取决于事务中的代码是否运行成功。当脚本结束或连接即将关闭时,如果有未完成的事务,PDO会自动回滚。这是一个安全的解决方案,以防脚本意外终止,如果事务未明确提交,它将假设发生了一些错误并执行回滚以确保数据安全。自动回滚仅发生在通过beginTransaction()建立的事务中。如果手动执行启动事务的查询,PDO无法知道发生了什么,也无法回滚。代码如下:beginTransaction();for($i=0;$i<1000000;$i++){$conn->exec("insertinto`users`values(null,'username')");}//提交事务$conn->commit();}catch(PDOException$ex){//执行回滚$conn->rollBack();}注意:因为使用了事务,所以要么成功,要么失败。如果发现第一个执行了,而第二个没有执行或执行失败,则应检查表类型是否为MyISAM。MyISAM引擎不支持事务。您需要使用InnoDB或其他支持事务的引擎。