webman 项目需用 laudis/neo4j-php-client 实现稳定 bolt 连接,须注册为容器单例、显式启用 throwonerror、限制深度查询并定期清理空闲连接。

Webman 项目能直接连 Neo4j,但默认不带客户端,必须用 laudis/neo4j-php-client 才能稳定走 Bolt 协议、支持事务和集群路由——别试原生 cURL 或自己封装,会卡在连接复用和超时重试上。
Webman 中配置 laudis/neo4j-php-client 客户端
Webman 是基于 Swoole 的常驻内存框架,不能像传统 PHP 那样每次请求新建 Client 实例。必须把 Client 注册为容器单例,否则连接数暴涨、Bolt 连接池失效。
在 config/container.php 里加:
use Laudis\Neo4j\ClientBuilder;
use Laudis\Neo4j\Contracts\ClientInterface;
return [
ClientInterface::class => function () {
return ClientBuilder::create()
->withDriver('bolt', 'bolt://neo4j:7687')
->withAuth('neo4j', 'your_password')
->withConnectionPoolSize(20) // 根据并发调,别盲目设 100
->build();
},
];
注意三点:
-
withDriver('bolt', ...)必须显式指定,HTTP 驱动在 Webman 下无法复用连接,会触发 Swoole 协程上下文丢失 - 密码不能硬编码,应从
config/.env读取,比如env('NEO4J_PASSWORD') -
withConnectionPoolSize建议设为 Webman worker 数 × 3~5,太大反而导致 Neo4j 服务端拒绝连接
在 Controller 或 Service 中安全执行 Cypher 查询
Webman 的协程环境下,auto-commit 查询看似简单,但遇到网络抖动或 Neo4j 重启时会静默失败,且不抛异常——因为底层 Bolt 驱动默认关闭了 throwOnError。
正确写法是显式启用错误传播:
$client = container()->get(ClientInterface::class);
try {
$result = $client->run(
'MATCH (u:User {id: $id})-[:FRIEND]->(f) RETURN f.name AS name',
['id' => $userId]
)->enableThrowOnError(); // 关键!否则 silent fail
return $result->toArray();
} catch (Laudis\Neo4j\Exception\Neo4jException $e) {
Log::error('Neo4j query failed', ['error' => $e->getMessage()]);
throw new RuntimeException('社交关系查询不可用');
}
常见坑:
- 参数必须用命名占位符
$id,别用?,否则类型推导失败,整数被当字符串传入 - 不要在事务外用
run()处理写操作,Webman 的长连接生命周期下,未提交事务可能滞留数分钟 - 返回的
Record对象不能直接json_encode,要先调toArray()或get('name')
处理深度关系遍历(如“朋友的朋友”)的性能陷阱
Cypher 写 MATCH (u)-[:FRIEND*2..3]->(target) 看似简洁,但在 Webman 高并发下极易触发 Neo4j 的 dbms.memory.pagecache.size 溢出,表现为查询延迟突增至秒级甚至超时。
优化策略不是改 Cypher,而是分层控制:
- 前端传参限制最大跳数,比如只允许
depth=2,后端校验并拒绝depth > 3 - 对高频路径(如“共同好友”)加 Redis 缓存,key 用
common_friends:{uid1}_{uid2},TTL 设 30 分钟 - 真正需要深度遍历时,改用
transactionFunction+retryLogic,避免单次长事务锁表
示例:
$client->transactional(function (TransactionInterface $tx) use ($startId) {
$result = $tx->run(
'MATCH (u:User {id: $id})-[:FRIEND*1..2]->(f) WHERE NOT (u)-[:FRIEND]->(f) RETURN f.id',
['id' => $startId]
);
return $result->list('f.id');
});
最易被忽略的是 Bolt 连接的 keep-alive 行为:Webman 不会自动关闭空闲 Bolt 连接,而 Neo4j 默认 30 分钟才清理,这会导致连接池缓慢泄漏。建议在 config/autoload/processes.php 里加一个定时器,每 15 分钟调一次 $client->closeIdleConnections()。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











