当前位置: 首页 > news >正文

PHP语法高级篇(七):MySQL数据库

Web编程不可避免的需要使用到数据库,而MySQL数据库使用的非常多,并且是LAMP(Linux+Apache+MySQL+PHP)的技术栈的核心组合。本篇文章将记录PHP操作MySQL的学习过程。


一、连接 MySQL

PHP 5 及更高版本可以使用以下方式与 MySQL 数据库协同工作:

  • MySQLi 扩展("i" 代表 improved,即改进)
  • PDO(PHP Data Objects,即 PHP 数据对象)

本篇文章将记录如何使用 PDO 进行 MySQL 数据库操作。为什么选择 PDO?是因为在之后会记录 ThinkPHP 框架的学习,而在该框架中,数据库的操作是基于 PDO 的,所以这里只选择 PDO 进行学习。

连接是通过创建 PDO 基类的实例而建立的。使用哪种驱动程序并不重要,始终都会用 PDO 类名。构造函数接受用于指定数据库源以及可选的用户名和密码(如果有)的参数。

示例 打开连接

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
} catch (PDOException $e) {echo "连接失败";
}

连接数据库成功后,返回 PDO 类的实例给脚本。此连接在 PDO 对象的生存周期中保持有效状态。要关闭连接,需要确保删除它的所有剩余引用来销毁对象——可以通过对对象变量赋值 null 来实现。如果没有明确这么做,PHP 在脚本结束时会自动关闭连接。

示例 关闭连接

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass);// 一些代码...$conn = null; // 关闭连接
} catch (PDOException $e) {echo "连接失败";
}

还可以创建数据库持久连接。持久连接不会在脚本结束时关闭,而是会缓存,且当另一个脚本使用相同凭证请求连接时重用。持久连接缓存可以避免每次脚本需要与数据库通信时建立新连接的开销,从而让 web 应用程序更快。

示例 持久化连接

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
} catch (PDOException $e) {echo "连接失败";
}

二、预处理语句

很多更成熟的数据库都支持预处理语句的概念。什么是预处理语句?可以把它看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句可以带来两大好处:

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

下面我们来创建一张用于程序测试的表格:

CREATE TABLE test(  id int NOT NULL PRIMARY KEY AUTO_INCREMENT,name VARCHAR(255),value VARCHAR(255)
);

稍后我们将通过示例来说明如何使用预处理语句来完成数据库表的增、删、改、查操作。

1、事务与自动提交

数据库操作是离不开事务的,在开始进行查询前,必须先理解 PDO 是如何管理事务的。

当第一次打开连接时,PDO 将在所谓的"自动提交"模式下运行。自动提交模式意味着,如果数据库支持,运行的每个查询都有它自己的隐式事务,如果数据库不支持事务,则没有。如果需要一个事务,则必须用 PDO::beginTransaction() 方法来启动。如果底层驱动不支持事务,则抛出一个 PDOException 异常。一旦开始了事务,可用 PDO::commit() 或 PDO::rollBack() 来完成,这取决于事务中的代码是否运行成功。

2、插入数据

首先,我们先来看一个使用预处理语句进行插入数据的示例:

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));// 1、通过用 name 和 value 替代相应的命名占位符来执行一个插入查询 $stmt = $conn->prepare("INSERT INTO test (name, value) VALUES (:name, :value)");$stmt->bindValue(':name', 'zhangsan');$stmt->bindValue(':value', 'one');$stmt->execute(); // 执行// 2、通过用 name 和 value 取代 ? 占位符的位置来执行一条插入查询$stmt = $conn->prepare("INSERT INTO test (name, value) VALUES (?, ?)");$stmt->bindValue(1, 'lisi');$stmt->bindValue(2, 'two');$stmt->execute(); // 执行// 关闭连接$stmt = null;$conn = null;
} catch (PDOException $e) {echo "连接失败";
}

现在对示例进行一下说明:

1、PDO::prepare:预处理要执行的语句,并返回语句对象。

public PDO::prepare(string $query, array $options = []): PDOStatement|false

为 PDOStatement::execute() 方法传入预处理待执行的 SQL 语句。语句模板可以包含零个或多个参数占位标记,格式是命名(:name)或问号(?)的形式,当它执行时将用真实数据取代。在同一个语句模板里,命名形式和问号形式不能同时使用,只能选择其中一种参数形式。

参数

query

必需。必须是对目标数据库服务器有效的 SQL 语句模板。

options

可选。数组包含一个或多个 key=>value 键值对,为返回的 PDOStatement 对象设置属性。常见用法是:设置 PDO::ATTR_CURSOR 为 PDO::CURSOR_SCROLL,将得到可滚动的光标。某些驱动有驱动级的选项,在 prepare 时就设置。

返回值 

如果数据库服务器已经成功预处理语句,PDO::prepare() 返回 PDOStatement 对象。如果数据库服务器无法预处理语句,PDO::prepare() 返回 false 或抛出 PDOException。

2、PDOStatement:PDO::prepare() 预处理语句成功后会返回该对象。代表一条预处理语句,并在该语句被执行后代表一个相关的结果集。

3、PDOStatement::bindValue:绑定一个值到用作预处理的 SQL 语句中的对应命名占位符或问号占位符。

public PDOStatement::bindValue(string|int $param, mixed $value, int $type = PDO::PARAM_STR): bool

参数

param

必需。参数标识符。对于使用命名占位符的预处理语句,应是类似 :name 形式的参数名。对于使用问号占位符的预处理语句,是以1开始索引的参数位置。

value

必需。绑定到参数的值。

type

可选。使用 PDO::PARAM_* 常量明确地指定参数的类型。

返回值

成功时返回 true, 或者在失败时返回 false。

 注意:bindValue() 方法只能绑定值,如果要绑定变量,需要使用 bindParam() 方法。

注意:bindValue() 方法只能绑定值,如果要绑定变量,需要使用 bindParam() 方法。

3、查询数据 

现在,我们将刚才插入的数据使用查询语句将其显示在页面上:

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));$stmt = $conn->prepare('SELECT id, name, value FROM test');$stmt->execute();foreach ($stmt as $row) {echo 'id:' . $row['id'] . ',name:' . $row['name']. ',value:' . $row['value'] . '<br>';}// 关闭连接$stmt = null;$conn = null;
} catch (PDOException $e) {echo "连接失败";
}

现在对示例进行一下说明:

1、PDOStatement:代表一条预处理语句,并在该语句被执行后代表一个相关的结果集。可以使用 foreach 语句对其进行遍历,其中查询的每条记录以关联数组的形式进行存储,可以使用 $row[列名] 的方式得到指定列的数据。

4、修改数据 

我们将 zhangsan 对应的 value 更改为大写的”ONE“。

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));$stmt = $conn->prepare('UPDATE test SET value=:value WHERE name=:name');$value = 'ONE';$name = 'zhangsan';$stmt->bindParam("value", $value);$stmt->bindParam("name", $name);$stmt->execute();echo $stmt->rowCount() . '条记录被更新';// 关闭连接$stmt = null;$conn = null;
} catch (PDOException $e) {echo "连接失败";
}

现在对示例进行一下说明:

1、PDOStatement::bindParam 方法与 PDOStatement::bindValue 做的事情相同,不同的是:bindParam() 方法绑定的是变量,bindValue() 方法绑定额是值。

2、PDOStatement::rowCount:返回受上一个 SQL 语句影响的行数。

5、删除数据

将 name 为 "zhangsan" 的数据进行删除。

<?php
try {$user = 'root'; // 数据库用户名$pass = '123456'; // 数据库密码$conn = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));$stmt = $conn->prepare('DELETE FROM test WHERE name=:name');$stmt->bindValue('name', 'zhangsan');$stmt->execute();echo $stmt->rowCount() . '条记录被删除';// 关闭连接$stmt = null;$conn = null;
} catch (PDOException $e) {echo "连接失败";
}

该示例没有什么需要进行说明的,操作的方法与上面的修改数据是一样的。

到这里,本篇文章记录了如何进行数据库连接、增删改查操作,更多的关于PHP数据库的内容,可以查看 数据库扩展 进行学习。

这篇文章是PHP语法学习的最后一篇文章,从下一篇文章开始,将记录 ThinkPHP 8 的学习过程。

http://www.lryc.cn/news/605138.html

相关文章:

  • OSS-服务端签名Web端直传+STS获取临时凭证+POST签名v4版本开发过程中的细节
  • Spring AOP详细解析
  • [硬件电路-106]:模拟电路 - 电路为什么会出现不同的频率特性?元件频率依赖性、信号传输路径、电路拓扑结构、外部因素
  • 【maven】仓库配置
  • Matrix Theory study notes[6]
  • USRP捕获手机/路由器数据传输信号波形(上)
  • ZKMall商城开源本地部署指南
  • Apache Ignite 集群标识(Cluster ID)和集群标签(Cluster Tag)
  • 【物联网】基于树莓派的物联网开发【18】——树莓派安装Mosquitto服务
  • anaconda和Miniconda安装包32位64位皆可,anaconda和Miniconda有什么区别?
  • 2419. 按位与最大的最长子数组
  • 【 建模分析回顾】[MultiOutputClassifier]MAP - Charting Student Math Misunderstandings
  • mac升级安装python3
  • LeetCode 53 - 最大子数组和
  • 【Unity3D实例-功能-移动】复杂移动(Blend Tree方式)
  • JeecgBoot(1):前后台环境搭建
  • 【Excel】制作双重饼图
  • Linux设备驱动架构相关文章
  • 学习日志22 python
  • CUDA编程9 - 卷积实践
  • Python - 元类
  • 离散扩散模型在数独问题上的复现与应用
  • RAG工作流程总览
  • 解析非法获取计算机信息系统数据罪中的其他技术手段
  • 《超级秘密文件夹》密码遗忘?试用版/正式版找回教程(附界面操作步骤)
  • IATF 16949详解(腾讯混元)
  • Oracle11g数据库迁移达梦8数据库方案
  • 论文阅读|CVPR 2025|Mamba进一步研究|GroupMamba
  • 领域驱动设计(DDD)在分布式系统中的架构实践
  • cpp实现音频重采样8k->16k及16k->8k