一、Mysqli扩展
注意:使用Mysqli扩展之前,不要忘了启用。使用Wamp集成环境的可以界面操作启用,当然也可以去php.ini启用。
连接数据库
// 最后一个参数,一般不传
$link = new mysqli(主机名, 用户名, 密码, 数据库名, 端口号, socket);
// 连接错误判断
if ($link->connect_errno) { // 错误代码。连接成功返回0
echo "连接失败" . $link->connect_error; // 打印错误信息
die();
}
// 连接成功,不要忘了设置连接的字符集,否则可能会遇到乱码
$link->set_charset("utf8");
查询操作
1、逐行取出
// 从结果集中取数据
// 逐行取出,取出一行后,游标会指向下一行
// 返回一个索引数组。对应结果集的一条数据(一行)
$row = $result->fetch_row();
// 返回一个关联数组。数组索引与数据库表的字段名一样
$row = $result->fetch_assoc();
// 通过循环,取出结果集的所有数据
while (($row = $result->fetch_row()) != null) {
// 取出字段
$row[0]
$row[1]
}
while (($row = $result->fetch_assoc()) != null) {
// 取出字段
$row['字段名1']
$row['字段名2']
}
2、一次性取出
$rows = $result->fetch_all(返回数组的类型)
返回数组的类型:
MYSQLI_NUM // 以索引数组形式返回
MYSQLI_ASSOC // 以关联数组形式返回
foreach ($rows as $row) {
// 取出字段
}
3、资源释放
// 释放结果集
$result->free();
// 释放数据库连接
$link->close();
4、特殊需求
// 结果集对象中的属性,而不是方法
$result->num_rows;
增、删、改操作
1、执行和操作判断
$sql = "..."; // 增、删、改的sql语句
// 增、删、改操作返回的是布尔类型
$bool = $link->query($sql);
// 除了通过这个布尔值判断是否成功外,还可以通过受影响的行数判断
if (($bool !== false) && ($link->affected_rows > 0)) {
// 操作成功
}
2、特殊需求:如果是insert操作,需要最后插入的数据的【自增长id】(非自增长的不行)
// 在执行完insert语句之后,可通过下面代码获取自增长id
$link->insert_id; // 数据库连接对象的一个属性,而不是方法
3、关闭数据库连接,操作同上
预处理语句机制
1、假如我要插入多条数据,sql语句都差不多,就是每一条sql语句中的数据不一样(特点)。如果不使用预处理语句机制,而是逐条sql语句执行,效率比较低。针对这种情况,PHP向MySQL发送一个需要执行的sql模板,由于数据不同,sql语句中数据部分用占位符“?”表示,然后再单独发送数据。因此,可以向一个相同的准备语句发送大量的数据,大大提高了查询执行速度。
2、如果是增、删、改操作,使用预处理语句机制,可以防止sql注入。如果是查询操作,也可不必担心这种风险,因此可不必使用这种预处理机制。
1、插入多条数据 的完整使用流程
// 带有占位符的sql语句
$sql = " insert into user(id, username, password, age)
values(null, ?, ?, ?) ";
// 获取一个准备语句对象
$stmt = $link->prepare($sql);
// 绑定参数(将占位符跟变量绑定)
$username = null;
$password = null;
$age = null;
$stmt->bind_param("ssi", $username, $password, $age);
/*
* 1、绑定的是变量的【引用】(引用传递)
* 2、第一个参数表示变量类型:
* i:所有INTEGER类型
* d:DOUBLE和FLOAT类型
* b:BLOB类型
* s:所有其他类型,包括字符串
* 字符串中的第i个字符,对应后面第i个变量的类型
* 例如:"ssi"的第3个字符'i'表示,后面第三个变量$age是Integer类型
*/
// 插入一条数据
// 由于$stmt绑定了变量的【引用】,所以只需为变量赋值,然后执行即可
$username = "小明";
$password = "123";
$age = 12;
$stmt->execute();
// 再插入一条
$username = "李华";
$password = "233";
$age = 13;
$stmt->execute();
// 关闭$stmt
$stmt->close();
2、查询 操作的完整流程示例
可以看出来,它是通过将结果集中的 每一行数据的各个字段绑定到各个变量上,然后通过$stmt->fetch(),移动结果集中的游标,并取出一行数据赋值到变量中。
个人觉得如果是查询操作,没必要这么干。用前面的操作更方便。
二、PDO扩展
PDO扩展类库为PHP访问数据库定义了一个轻量级的、一致性的接口,它提供了一个数据访问抽象层,这样,无论使用什么样的数据库,都可以通过一致的函数执行查询和获取数据。 大大简化了PHP对数据库的操作,并能够屏蔽不同数据库之间的差异。使用PDO可以很方便地进行跨数据库程序的开发,以及不同数据库间的移植。
说白了,总结几句话:
1、PDO类似Java中的JDBC,是PHP与各种数据库交互的接口层
2、Mysqli扩展只针对于PHP与MySQL数据库进行交互,而使用PDO可以跟各种数据库进行交互
此处,仍以PDO操作MySQL数据为例,介绍PDO。
注意,使用扩展前,记得启用!!!
插入多条数据完整实例
从下面代码,可以看出,插入一条数据也可以用下面代码实现
// 创建pdo对象
$dsn = "mysql:dbname=test;host=localhost";
$username = 'root';
$password = '123';
try {
$pdo = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo '数据连接失败:' . $e->getMessage();
exit();
}
// 获取准备语句对象
$sql = " insert into user(id, username, password, age)
values(null, ?, ?, ?) ";
$stmt = $pdo->prepare($sql);
// 直接在execute中以数组形式传入参数值,代替占位符
// 注意,数组的值要与占位符一一对应
$stmt->execute(array('小明', '123', 12));
$stmt->execute(array('李华', '233', 13));
// 当然也可以像前面Mysqli里面的预处理机制一样
// 先绑定变量,再给变量赋值,再执行
查询操作示例
$sql = " select * from user where age=? ";
$stmt = $pdo->prepare($sql);
$bool = $stmt->execute(array(12)); // 为占位符赋值,然后执行
if ($bool === true) {
// 12岁的user可能不只一个,故返回的数组是二维数组(可想象为一张表)
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); // 以关联数组形式返回
}
PDO扩展的封装
可以看出来,PDO扩展的代码简单明了。参考教材,实现PDO的基本封装,简化以后我们数据库操作的代码量
<?php
/**
* @author passerbyYSQ
* @create 2020年4月17日 下午3:41:53
*/
require_once 'config/config.php';
class DbDao {
// 注意这里有static。在构造函数里,确保$db单例
protected static $db = null;
public function __construct() {
// 确保$db单例
isset(self::$db) || self::connect();
}
private static function connect() {
// 获取配置
$config = require_once SA_PATH . '/config/db_config.php';
$dsn = "{$config['type']}:host={$config['host']};port={$config['port']};
dbname={$config['dbname']};charset={$config['charset']}";
try {
self::$db = new PDO($dsn, $config['user'], $config['pwd']);
} catch (PDOException $e) {
echo '连接错误!<br/>';
echo '错误文件:'.$e->getFile().'<br/>';
echo '错误行号:'.$e->getLine().'<br/>';
echo '错误描述:'.$e->getMessage().'<br/>';
die();
}
}
public function query($sql, $parms, $batch = false, &$ids = null) {
$data = $batch ? $parms : array($parms);
$stmt = self::$db->prepare($sql);
foreach ($data as $v) {
if ($stmt->execute($v) === false) {
var_dump($stmt->errorInfo()); // 用于调试
if ($ids !== null) {
$ids = null;
}
return null;
} else {
if ($ids !== null) {
$ids[] = self::$db->lastInsertId();
}
}
}
return $stmt;
}
/**
* 插入多条数据
* @param unknown $sql 带有占位符的sql语句
* @param unknown $parms 参数值。由于是多条数据,故应传入一个二维数组(索引数组)
* @param unknown $auto 是否是自增长Id。默认Id是自增长的。
* @return array 如果全部插入成功,返回一个索引数组,每个元素对应插入的每条记录的自增长id
* 注意主键需要是自增长的id。若Id非自增长,返回受影响的行数
*/
public function insertMul($sql, $parms, $auto = true) {
if ($auto === true) {
// id自增长的情况
$lastIds = array();
$this->query($sql, $parms, true, $lastIds);
return $lastIds;
} else {
// id非自增长的情况
$stmt = $this->query($sql, $parms, true);
return $stmt->rowCount();
}
}
/**
* 插入一条数据
* @param unknown $sql 带有占位符的sql语句
* @param unknown $parms 参数值。应为一维数组(索引数组)
* @return 自增长id
*/
public function insertOne($sql, $parms, $auto = true) {
if ($auto === true) {
// id自增长的情况
$this->query($sql, $parms);
return self::$db->lastInsertId();
} else {
// id非自增长的情况
$this->query($sql, $parms);
}
}
// 查询全部数据
public function selectAll($sql, $parms) {
return $this->query($sql, $parms)->fetchAll(PDO::FETCH_ASSOC);
}
// 查询一条数据
public function selectOne($sql, $parms) {
return $this->query($sql, $parms)->fetch(PDO::FETCH_ASSOC);
}
// 修改或删除。返回受影响行数
public function updateOrDelete($sql, $parms) {
return $this->query($sql, $parms)->rowCount();
}
// 获取行数
public function getCount($table, $where = '') {
$sql = ' select count(*) from ' . $table . $where;
$result = self::$db->query($sql);
return $result->fetch()[0];
}
}
?>
这是pdo基础操作的封装。使用时,将它作为基类来继承,扩展更复杂的业务操作