Erlang ODBC报错process_not_owner_of_odbc_connection求助
解决Erlang ODBC
{:error, :process_not_owner_of_odbc_connection} 错误的方案 我之前也碰到过这个问题!这个错误的核心原因其实是Erlang ODBC的连接和创建它的进程是强绑定的——只有创建连接的那个进程(也就是owner进程)才能对这个连接执行操作,其他进程直接拿这个连接PID去调用:odbc系列函数肯定会触发权限错误。
针对你写连接池的需求,这里有几个可行的解决方案:
1. 让GenServer作为连接持有者,代理所有数据库操作
不要把连接PID从GenServer里取出来给其他进程用,而是让其他进程通过GenServer的调用接口,把查询请求发送给GenServer,由GenServer(连接的owner)去执行ODBC操作。
举个简单的GenServer实现示例:
defmodule ODBCPoolWorker do use GenServer # 客户端调用接口 def start_link(conn_opts) do GenServer.start_link(__MODULE__, conn_opts) end def perform_query(server_pid, sql, params) do GenServer.call(server_pid, {:param_query, sql, params}) end # 服务端回调 @impl true def init(conn_string) do case :odbc.connect(conn_string, []) do {:ok, conn} -> {:ok, conn} {:error, reason} -> {:stop, reason} end end @impl true def handle_call({:param_query, sql, params}, _from, conn) do result = :odbc.param_query(conn, sql, params) {:reply, result, conn} end end
然后你的连接池只需要管理多个这样的ODBCPoolWorker进程即可——当需要查询时,从池里取出一个worker的PID,调用perform_query/3,由worker去执行实际的ODBC操作。
2. 使用成熟的第三方连接池库
没必要自己从零写连接池,Erlang生态里有很多现成的工具可以直接用,比如:
- poolboy:最常用的通用进程池库,你可以把每个worker配置成上面的
ODBCPoolWorker,让poolboy帮你管理worker的创建、复用和销毁。 - db_connection:官方的数据库连接行为库,可用来封装ODBC连接,配合
poolboy实现连接池,能帮你处理连接超时回收、故障重启等边界问题。
用现成库的好处是能避免很多重复造轮子的坑,节省开发和调试时间。
3. 自定义连接池:让每个连接对应独立进程
如果一定要自己实现连接池,核心思路是每个ODBC连接都由一个独立的进程持有,池进程只负责维护这些连接进程的列表,以及处理请求的分发:
- 池启动时,创建指定数量的连接进程(每个进程自己创建ODBC连接)
- 当有查询请求时,池从可用列表中选出一个连接进程,把查询请求转发给它
- 连接进程执行完查询后,把结果返回给请求方,自己回到可用列表
这种方式下,每个连接的owner都是对应的连接进程,永远不会出现“非owner进程操作连接”的问题。
内容的提问来源于stack exchange,提问作者Botonomous
相关产品推荐
相关产品推荐

