PHP 使用 findAndModify 为 MongoDB 实现原子性自增 ID
MongoDB 原生并不支持自增主键,但在特定业务逻辑下可能仍需使用该特性。本文介绍如何通过 PHP 驱动程序,利用 MongoDB 的 `findAndModify` 命令配合原子更新操作 `$inc`,构建一个用于生成自增 ID 的可靠机制。
实现原理
MongoDB 的 findAndModify 是一个复合操作,它可以在一次数据库命令中同时完成“查找文档”和“更新文档”两个动作,且该过程具备原子性,能够有效防止并发环境下的重复或错乱问题。
实现思路如下:
- 建立序列计数器集合:预先创建一个单独的集合(通常命名为
ids),其中包含记录不同序列名称及其当前数值的文档。 - 执行原子递增:在插入新数据前,针对特定的序列名称(如 "user"),使用
findAndModify命令执行$inc: { id: 1 }操作。该命令会按条件找到对应文档,将其 ID 加 1,并返回更新后的整个文档。 - 提取并使用:从返回结果中提取最新的 ID 值,随后进行正常的业务数据保存。
准备序列计数器
首先需要确保存有计数器数据的集合存在。若不存在,可以手动插入一条初始记录,初始化某个序列的值。例如,初始化名为 "user" 的用户序列:
db.ids.save({name:"user", id:0});
通过 db.ids.find() 可验证是否创建成功。
核心自增方法
以下是一段 PHP 代码示例,演示了如何封装这一过程。该函数接收序列名和数据库连接对象,利用 MongoDB 的 command 方法进行跨语言操作。
代码说明
<?php
// 自定义获取自增 ID 的函数
function mid($name, $db){
// 定义更新操作:将字段 'id' 增加 1
$update = array('$inc'=>array("id"=>1));
// 定义查询条件:匹配序列名称
$query = array('name'=>$name);
// 构造 MongoDB 的 findAndModify 命令参数
$command = array(
'findandmodify' => 'ids', // 指定操作的集合
'update' => $update, // 更新规则
'query' => $query, // 查找条件
'new' => true, // 返回更新后的文档
'upsert' => true // 如果未找到文档,则创建新的
);
// 发送命令并执行
$id = $db->command($command);
// 提取并返回递增后的 ID 数值
return $id['value']['id'];
}
// 连接 MongoDB
$conn = new Mongo();
$db = $conn->idtest;
// 调用函数获取自增 ID
$id = mid('user', $db);
// 使用该 ID 保存用户信息
db->user->save(array(
'uid' => $id,
'username' => 'kekeles',
'password' => 'kekeles',
'info' => 'https://www.jb51.net/ '
));
// 关闭连接
$conn->close();
?>
关键参数解析
- upsert => true:这是保障健壮性的关键设置。如果尝试获取的序列名(如 "admin")在
ids集合中尚不存在,MongoDB 会自动为该序列创建一条初始记录,而不会报错中断程序。 - new => true:表示命令返回的是更新之后的文档内容。这使我们能够直接从返回值中拿到最新递增的 ID 值。
完成判断
运行上述脚本后,可以通过 MongoDB Shell 或其他客户端工具查询数据验证结果:
db.user.find();
预期将在 user 集合中看到插入的记录,其中 uid 字段已成功设置为自增的整数值。
简要总结
借助 MongoDB 的 findAndModify 和 $inc 原语,PHP 程序可以安全、高效地实现自增 ID 功能。这种方式避免了应用层锁带来的性能瓶颈,同时也具有较好的可扩展性,可以实现类似 Oracle 等多表间隔离的自增序列体系。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









