ThinkPHP8学习篇(八):数据库(四)
在数据库操作的完整链路中,除了基础查询与进阶查询能力外,查询事件的钩子机制、数据获取的格式化处理、事务操作的原子性保障以及数据集的高效处理,共同构成了数据库操作的闭环增强体系,是提升代码健壮性与开发效率的重要支撑。本篇作为数据库系列文章的最后一篇,学习核心内容将集中在查询事件的注册与触发机制、获取器对数据输出的格式化处理、事务操作的开启/提交/回滚流程、以及数据集的遍历与转换等实用功能上。本篇文章将记录 ThinkPHP 数据库操作中这些增强特性的学习过程。
一、查询事件
数据库操作的回调也称为查询事件,是针对数据库的CURD操作而设计的回调方法,主要包括:
事件 | 描述 |
before_select | select查询前回调 |
before_find | find查询前回调 |
after_insert | insert操作成功后回调 |
after_update | update操作成功后回调 |
after_delete | delete操作成功后回调 |
使用 Db 类的 event 方法注册数据库查询事件。注册的代码可以写入到 app/AppService.php 中的 register() 服务注册方法中。
示例
// 代码位于 app/AppService.php 中的 register 方法内
public function register()
{// 注册 before_select 事件Db::event('before_select', function($query) {// 事件处理,可以编写对应的处理代码// 在这里也可以对 $query 进行操作,例如:在当前的 select 查询中对查询结果根据 id 进行 desc 排序$query->order('id', 'asc');});
}
不需要在事件中返回任何东西。
同一个查询事件可以注册多个响应执行。查询事件的方法参数只有一个:当前的查询对象。但可以通过依赖注入的方式添加额外的参数。
二、获取器
在 ThinkPHP 中,获取器是用于对字段值进行格式化处理的特殊方法。它允许你在获取字段数据时,自动对原始数据进行加工、转换或处理,而无需在每次使用数据时手动处理。
Db 类可以支持获取器定义,例如:
Db::table('user')->withAttr('name', function($value, $data) {// 将 name 字段的值会统一进行小写转换return strtoupper($value);
})
->select();
获取器方法支持传入两个参数,第一个参数是当前字段的值,第二个参数是所有的数据。
withAttr 方法可以多次调用,对多个字段定义获取器。
新版本增加了查询结果处理机制,使用 filter 方法可以更方便的处理查询结果数据:
Db::table('user')->filter(function($user) {// $user 为当前查询记录$user['name'] = strtoupper($user['name']); // 将 name 字段的值会统一进行小写转换return $user; // 需要 return 返回更改的内容
})
->select();
三、事务操作
使用事务处理的话,需要数据库引擎支持事务处理。比如 MySQL 的 MyISAM 不支持事务处理,需要使用 InnoDB 引擎。
最简单的方式是使用 transaction 方法操作数据库事务,当闭包中的代码发生异常会自动回滚。例如:
Db::transaction(function () {Db::table('user')->find(1);Db::table('user')->delete(1);
});
也可以手动控制事务。例如:
// startTrans() 方法启动事务
Db::startTrans();
try {Db::table('user')->find(1);Db::table('user')->delete(1);// commit() 方法提交事务Db::commit();
} catch (\Exception $e) {// rollback() 方法回滚事务Db::rollback();
}
注意:在事务操作的时候,确保数据库连接使用的是同一个。
四、数据集
数据库的查询结果默认返回数据集对象。
示例
// 获取数据集
$users = Db::name('user')->select();
// 遍历数据集
foreach($users as $user){echo $user['name'];echo $user['id'];
}
返回的数据集对象是 think\Collection,提供了和数组无差别用法,并且另外封装了一些额外的方法。
可以直接使用数组的方式操作数据集对象。例如:
// 获取数据集
$users = Db::name('user')->select();
// 直接操作第一个元素
$item = $users[0];
// 获取数据集记录数
$count = count($users);
// 遍历数据集
foreach($users as $user){echo $user['name'];echo $user['id'];
}
需要注意的是,如果要判断数据集是否为空,不能直接使用 empty 方法判断,而必须使用数据集对象的 isEmpty 方法判断。例如:
$users = Db::name('user')->select();
if($users->isEmpty()){echo '数据集为空';
}
Collection 类主要包含以下方法:
方法 | 描述 |
isEmpty | 是否为空 |
toArray | 转换为数组 |
all | 所有数据 |
merge | 合并其它数据 |
diff | 比较数组,返回差集 |
flip | 交换数据中的键和值 |
intersect | 比较数组,返回交集 |
keys | 返回数据中的所有键名 |
pop | 删除数据中的最后一个元素 |
shift | 删除数据中的第一个元素 |
unshift | 在数据开头插入一个元素 |
push | 在结尾插入一个元素 |
reduce | 通过使用用户自定义函数,以字符串返回数组 |
reverse | 数据倒序重排 |
chunk | 数据分隔为多个数据块 |
each | 给数据的每个元素执行回调 |
filter | 用回调函数过滤数据中的元素 |
column | 返回数据中的指定列 |
sort | 对数据排序 |
order | 指定字段排序 |
shuffle | 将数据打乱 |
slice | 截取数据中的一部分 |
map | 用回调函数处理数组中的元素 |
where | 根据字段条件过滤数组中的元素 |
whereLike | Like查询过滤元素 |
whereNotLike | Not Like过滤元素 |
whereIn | IN查询过滤数组中的元素 |
whereNotIn | Not IN查询过滤数组中的元素 |
whereBetween | Between查询过滤数组中的元素 |
whereNotBetween | Not Between查询过滤数组中的元素 |