process_not_owner_of_odbc_connection:ODBC连接

时间:2018-03-05 18:42:14

标签: erlang odbc elixir

使用erlang odbc查询时是否有人遇到此错误:

  

{:error,:process_not_owner_of_odbc_connection}

我正在编写一个连接池,并且:ODBC.connect('conn string)在genserver中运行,返回的pid进入状态...但是当我从生成器服务器中取出PID时,尝试运行带有该pid的odbc.param_query时出现上述错误...如果我们可以使用在genserver中创建的pid,我们如何设置创建连接池?

有人有什么想法吗?

GenServer:

black

调用功能:

defmodule ItemonboardingApi.ConnectionPoolWorker do
    use GenServer

    def start_link([]) do
      IO.puts "Starting Connection Pool"
      GenServer.start_link(__MODULE__, nil, [])
    end

    def init(_) do
        :odbc.start
      {ok, pid} = :odbc.connect('DSN=;UID=;PWD=', [])
      IO.inspect pid
      {:ok, pid}
    end

    def handle_call(:get_connection, _from, state) do
      IO.puts "Inspecting State:"
      IO.inspect state
      IO.puts("process #{inspect(self())} getting odbc connection")
      {:reply, state, state}
    end
  end

我已经确认genserver中的pids会感染正确的odbc pids而GenServer.Call会返回其中一个。

**** **** EDIT 这是我为解决这个问题所做的工作。我不知道创建连接的进程必须是运行查询的进程。我的工作人员稍微改变一下,将查询传递给了我的问题。这是一个粗略的第一步,仍然需要对工人做一些事情。

def get_standards_like(standard) do
    :poolboy.transaction(
      :connection_pool,
      fn pid -> 
       connection = GenServer.call(pid, :get_connection) 
       IO.inspect connection

      val =
        String.upcase(standard)
        |> to_char_list

      # Call Stored Proc Statement
      spstmt = '{call invlibr.usp_vm_getStandards (?)}'

      case :odbc.param_query(connection, spstmt, [
             {{:sql_char, 50}, [val]}
           ])
           |> map_to_type(ItemonboardingCore.Standard) 
           do
        {:ok, mapped} ->
          {:ok, mapped}

        {:updated, affected_count} ->
          {:ok, affected_count}

        {:executed, o, a} ->
          {:ok, o, a}

        {:error, _} ->
          {:bad}
      end 
     end
    )
  end

2 个答案:

答案 0 :(得分:3)

这会成为一个问题,就像凯文指出的那样,你无法为odbc和其他驱动程序(如mysql / otp)转移连接所有权。

如果您想使用连接池,请改为https://github.com/mysql-otp/mysql-otp-poolboy

否则,您可以使用任何池,但执行sql查询的进程必须是打开连接的进程。

在Erlang中的

示例

sql_query_priv(Conn, Conn_Params, {SQL, Params}) ->
    lager:debug("~p:sql_query_priv trying to execute query: ~p, with params: ~p, conn = ~p~n", [?MODULE, SQL, Params, Conn]),
    case Conn of 
    null -> try mysql:start_link(Conn_Params) of
            {ok, NewConn} ->  
                  lager:info("~p:sql_query_priv Connection to DB Restored", [?MODULE]),
                  try mysql:query(NewConn, SQL, Params) of
                    ok ->  {ok, NewConn, []};
                    {ok, _Columns, Results} -> {ok, NewConn, Results};
                    {error, Reason} ->  
                        lager:error("~p:sql_query_priv Connection To DB Failed, Reason: ~p~n", [?MODULE, {error, Reason}]),
                       exit(NewConn, normal),
                       {error, null, Reason}                            
                  catch 
                    Exception:Reason -> 
                        lager:error("~p:sql_query_priv Connection To DB Failed, Exception:~p Reason: ~p~n", [?MODULE, Exception, Reason]),
                        {error, null, {Exception, Reason}} 
                  end;
            {error, Reason} ->  
                   lager:error("~p:sql_query_priv Connection To DB Failed, Reason: ~p~n", [?MODULE, {error, Reason}]),
                   {error, Conn, Reason}                            
            catch 
                Exception:Reason -> 
                    lager:error("~p:sql_query_priv Connection To DB Failed, Exception:~p Reason: ~p~n", [?MODULE, Exception, Reason]),
                    {error, Conn, {Exception, Reason}} 
            end;
    Conn -> try mysql:query(Conn, SQL, Params) of
                ok ->  {ok, Conn, []};
                {ok, _Columns, Results} -> {ok, Conn, Results};                      
                {error, Reason} ->  
                        try exit(Conn, normal) of
                         _Any -> ok
                        catch
                         _E:_R -> ok
                        end,
                      lager:error("~p:sql_query_priv Connection To DB Failed, Reason: ~p~n", [?MODULE, {error, Reason}]),
                      {error, null, Reason}                            
            catch 
                Exception:Reason -> 
                        try exit(Conn, normal) of
                         _Any -> ok
                        catch
                         _E:_R -> ok
                        end,
                      lager:error("~p:sql_query_priv Connection To DB Failed, Exception:~p Reason: ~p~n", [?MODULE, Exception, Reason]),
                      {error, null, {Exception, Reason}} 
            end
    end. 

答案 1 :(得分:2)

根据relevant documentationodbc连接对创建连接的Genserver进程是私有的。

  

打开与数据库的连接。该连接与   创建它的过程,只能通过它访问。这个   函数可能会生成新的进程来处理连接。这些   如果创建连接的进程将终止进程   死亡或如果你打电话给disconnect / 1。

您可以将其与可以设置为ETS的{​​{1}}表进行比较,但在private表的情况下,您可以将它们设为ETS。对于public个关联,这是不可能的,因此您应该将代码移到odbc