问题
ThinkPHP中对数据库的写入操作强制使用事务,而MongoDB在单机模式下是不支持事务的,需要使用集群才能支持事务,而分布式也是MongoDB的一个特性。所以在实际应用中,MongoDB总是以集群方式搭建的。但ThinkPHP手册总是以MySQL为例,没有详细介绍其他数据库的配置方式,所以还得从源码入手。
ThinkPHP对MongoDB的配置
ThinkPHP6中用于连接MongoDB的ORM是think-orm
,具体文件查看
https://github.com/top-think/think-orm/blob/2.0/src/db/connector/Mongo.php
初始化函数:initConnect
/**
* 初始化数据库连接
* @access protected
* @param boolean $master 是否主服务器
* @return void
*/
protected function initConnect(bool $master = true): void
{
if (!empty($this->config['deploy'])) {
// 采用分布式数据库
if ($master) {
if (!$this->linkWrite) {
$this->linkWrite = $this->multiConnect(true);
}
$this->mongo = $this->linkWrite;
} else {
if (!$this->linkRead) {
$this->linkRead = $this->multiConnect(false);
}
$this->mongo = $this->linkRead;
}
} elseif (!$this->mongo) {
// 默认单数据库
$this->mongo = $this->connect();
}
}
无论是否指定了deploy
等相关参数,流程最终都会走到这里:https://github.com/top-think/think-orm/blob/2.0/src/db/connector/Mongo.php#L167
if (empty($config['dsn'])) {
$config['dsn'] = 'mongodb://' . ($config['username'] ? "{$config['username']}" : '') . ($config['password'] ? ":{$config['password']}@" : '') . $config['hostname'] . ($config['hostport'] ? ":{$config['hostport']}" : '');
}
$startTime = microtime(true);
$this->links[$linkNum] = new Manager($config['dsn'], $config['params']);
...
最终都将拼接到dsn
字段中去,所以在配置文件中有两种写法
方式一
纯粹的字符串,只写dsn
和params
参数即可
'type' => 'mongo',
'dsn' => 'mongodb://root:123456@127.0.0.1:27017,127.0.0.1:27018',
'params' => ['authSource' => 'admin'],
'database' => 'test',
...
方式二
让ORM去拼接,将username
、password
、hostname
分开填写
'type' => 'mongo',
'hostname' => '127.0.0.1:27017,127.0.0.1:27018',
'params' => ['authSource' => 'admin'],
'database' => 'test',
'username' => 'root',
'password' => '123456',
...
个人推荐第一种URI方式,简单直接。
上面的例子等同于mongodb://root:123456@127.0.0.1:27017,127.0.0.1:27018/?authSource=admin
结论
不要被ThinkPHP的手册“迷惑”了,我们不需要理会deploy
、rw_separate
等参数。手册中提及的“分布式”、“读写分离”等名词和MongoDB的集群不是一个东西。
参考
分布式数据库
https://www.php.net/manual/en/mongodb-driver-manager.construct.php