如何在Postgres-nio Swift客户端中正确使用临时表执行查询?
Postgres-nio Swift客户端临时表操作异常的解决方案
我需要执行复杂查询,通过创建临时表存储并汇总数据,再获取最终的汇总结果。使用Postgres-nio Swift客户端时,尝试以下代码创建临时表,但始终报错提示找不到该表:
let results = try await withThrowingTaskGroup(of: Void.self, returning: ChangeData.self) { taskGroup in taskGroup.addTask { await client.run() } try await client.query("CREATE TEMP TABLE ABC (....)") try await client.query("INSERT INTO ABC (....) SELECT ... FROM XYZ") try await client.query("INSERT INTO ABC (....) SELECT ... FROM GHI") try await client.query("SELECT * FROM ABC") taskGroup.cancelAll() return storeChangeDate }
原本我是用数据库FUNCTION实现的,但为了把逻辑保留在客户端(避免随应用更新数据库函数,主要用于报表场景),所以想改用这种方式。
奇怪的是,如果先调用预准备语句执行Postgres函数,后续操作不会报错;但移除该函数调用后,插入操作就会提示临时表不存在。
编辑补充:后来发现Postgres-nio使用连接池,连续的查询请求未必会使用同一个数据库连接。目前的临时解决方案是把客户端最大连接数设为1,确保所有操作都在同一个Postgres会话里,但希望找到更合适的方法,比如直接从PostgresClient获取特定连接来执行所有相关操作?
正确解决方案:获取单个连接执行所有会话绑定操作
PostgreSQL的临时表是会话级的,只有创建它的数据库连接能访问到。Postgres-nio的client.query()默认会从连接池里随机取连接,所以后续的INSERT/SELECT可能跑到了另一个连接,自然找不到临时表。
你不需要把连接池最大连接数设为1,而是应该从连接池里获取一个单独的连接,用这个连接执行所有和临时表相关的操作,操作完成后再把连接放回池里。示例代码如下:
// 获取单个连接 let connection = try await client.connection() defer { // 操作完成后将连接放回池 connection.close() } // 用同一个连接执行所有临时表操作 try await connection.query("CREATE TEMP TABLE ABC (....)") try await connection.query("INSERT INTO ABC (....) SELECT ... FROM XYZ") try await connection.query("INSERT INTO ABC (....) SELECT ... FROM GHI") let result = try await connection.query("SELECT * FROM ABC") // 处理结果并返回 return storeChangeDate
另外,你之前用预准备语句执行函数时不报错,是因为预准备语句会绑定到某个连接,后续的查询可能复用了这个连接,刚好满足了会话一致性的要求,但这是偶然的,不是可靠的做法。
内容的提问来源于stack exchange,提问作者Duncan Groenewald
相关产品推荐
相关产品推荐

