【问题标题】:After a day or so of running, Windows service starts giving OracleExceptions when trying to perform query运行一天左右后,Windows 服务在尝试执行查询时开始给出 OracleExceptions
【发布时间】:2013-06-13 04:56:34
【问题描述】:

我在 .Net 4.0 中创建了一个 Windows 服务,其中需要对 Oracle 数据库做两件事。一种是运行 SELECT 查询以查看具有用户(通过电话 UI)ID 的记录是否存在,另一种是将新记录插入到表中。

一切正常,直到服务运行了一天左右 - 这里有一定程度的随机性,有时会运行几天,大多数情况下它只是在服务重新启动后运行 24 小时。

一旦出现问题,我就会开始收到 OracleExceptions。在这个问题的结尾处包含了一个完整的例外。异常表明打开到服务器的套接字要么失败,要么被“我的”机器上的软件关闭。

现在,有一些迹象表明这并不是真正的网络/数据库错误。

  1. 我有一个小型控制台实用程序,它使用完全相同的库代码从服务器读取。如果我在服务左右抛出异常的同时运行它,它可以毫无问题地使用数据库服务器验证数据。

  2. 如果我重新启动 Windows 服务,会立即恢复正常运行。

因此,在我的软件中使用一段时间后似乎有些东西会“厌倦”。现在,每次通话都会重新创建处理最终导致 Oracle 交互的电话呼叫的对象——希望那里不应该存在生命周期问题。同样,当这些对象需要与 Oracle 服务器通信时,会创建一个新的 OracleConnection 对象,并实例化一个新的 OracleCommand。这些和生成的 OracleDataReader 已关闭并显式处理(我什至停止使用 using() 模式以确保我真的在这样做)。这是代码的示例,在简化为几乎像孩子一样的东西以确保它做它应该做的事情之后:

    public bool CheckIfIdExists(string paramValue)
    {
        var result = false;

        var conn = new OracleConnection(_connectionString);
        conn.Open();
        var cmd = new OracleCommand("SQL query", conn)
        {
            CommandType = CommandType.Text
        };
        cmd.Parameters.Add("paramName", paramValue);

        var rdr = cmd.ExecuteReader();
        result = rdr.HasRows;

        rdr.Close();
        rdr.Dispose();

        cmd.Dispose();

        conn.Close();
        conn.Dispose();

        return result;
    }

如您所见,我在这里没有发现任何异常 - 它们在我的代码中得到进一步处理。它们发生在尝试打开连接时。

我没有必要的 Oracle 经验来了解为什么会失败。这非常令人沮丧,因为一旦重新启动服务,问题就会消失。是否有一些连接池突然干涸,因为我没有正确处理我的资源?

这是出现问题后尝试打开与服务器的连接时遇到的异常:

Unhandled exception occurred in HandleCall: Oracle.ManagedDataAccess.Client.OracleException (0x80004005): Network Session: Unexpected packet read error ---> OracleInternal.Network.NetworkException (0x80004005): Network Session: Unexpected packet read error ---> System.Net.Sockets.SocketException (0x80004005): An established connection was aborted by the software in your host machine
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
   at OracleInternal.Network.ReaderStream.Read(OraBuf OB)
   at OracleInternal.Network.ReaderStream.Read(OraBuf OB)
   at OracleInternal.TTC.OraBufReader.GetDataFromNetwork()
   at OracleInternal.TTC.OraBufReader.Read(Boolean bIgnoreData)
   at OracleInternal.TTC.TTCExecuteSql.ReceiveExecuteResponse(Accessor[]& defineAccessors, Accessor[] bindAccessors, Boolean bHasReturningParams, SQLMetaData& sqlMetaData, SqlStatementType statementType, Int64 noOfRowsFetchedLastTime, Int32 noOfRowsToFetch, Int32& noOfRowsFetched, Int64& queryId, Int32 longFetchSize, Int32 initialLOBFetchSize, Int64[] scnFromExecution, BindDirection[]& bindDirections, DataUnmarshaller& dataUnmarshaller)
   at Oracle.ManagedDataAccess.Client.OracleException.HandleError(OracleTraceLevel level, OracleTraceTag tag, Exception ex)
   at OracleInternal.TTC.TTCExecuteSql.ReceiveExecuteResponse(Accessor[]& defineAccessors, Accessor[] bindAccessors, Boolean bHasReturningParams, SQLMetaData& sqlMetaData, SqlStatementType statementType, Int64 noOfRowsFetchedLastTime, Int32 noOfRowsToFetch, Int32& noOfRowsFetched, Int64& queryId, Int32 longFetchSize, Int32 initialLOBFetchSize, Int64[] scnFromExecution, BindDirection[]& bindDirections, DataUnmarshaller& dataUnmarshaller)
   at OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteReader(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, OracleDataReaderImpl& rdrImpl, Int32 longFetchSize, Int32 lobPrefetchSize, OracleDependencyImpl orclDependencyImpl, Int64[] scnForExecution, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, Boolean isEFSelectStatement)
   at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior)
   at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader()
[...my code beyond this point...]

我考虑过进行一次 Wireshark 会话,以查看一旦出现此问题后网络级别实际发生的情况,但目前我真的不知道我在寻找什么,或者如果我能找到它会告诉我什么打开套接字的连接失败。

有谁知道这可能是什么原因造成的,可以采取什么措施?

非常感谢您的任何意见!

【问题讨论】:

  • 可能不相关,但您应该在 using 语句中包含 conncmdrdr 等,以便无论是否发生异常,它们都会被处理掉。目前,如果出现异常,它们会一直等待直到 GC 发生。
  • 同意,这(参见 ShellShock 的回答)正是我在问题开始出现之前所拥有的,我不得不尝试重新格式化代码以解决它......所以虽然我同意这是正确的方法,这显然不是问题。
  • 在代码中引入错误以尝试了解未知错误的原因是...一种新颖方法。假设我们在没有这些错误的情况下正确地重新编写了您发布的代码,那么在我们自己的头脑中,没有太多代码需要检查。没有什么明显的跳出来是不正确的。
  • 具体来说 - 我的生产代码或多或少 100% 等于您在下面 ShellShock 的答案中看到的代码。重写您在上面看到的内容是因为我不确定 Oracle,没有使用它的经验。所以我想明确说明关闭和处置,看看它在好的情况下是否有效,并且它仍然给我带来了问题。问题的性质让我认为随着时间的推移资源会“变坏”——也许是通过处置我破坏了某些资源池的对象?我不知道,只是在这一点上做实验。 :)

标签: c# oracle windows-services


【解决方案1】:

您应该使用“使用”块来确保及时处理资源,即使发生异常也是如此。先试试这个看看能不能解决问题:

public bool CheckIfIdExists(string paramValue)
{
    var result = false;

    using (var conn = new OracleConnection(_connectionString))
    {
      conn.Open();
      using (var cmd = new OracleCommand("SQL query", conn))
      {
        cmd.CommandType = CommandType.Text
        cmd.Parameters.Add("paramName", paramValue);

        using (var rdr = cmd.ExecuteReader())
        {
          result = rdr.HasRows;
        }
      }
    }

    return result;
}

【讨论】:

  • 感谢您的建议。不幸的是,当问题开始出现时,这或多或少正是我的代码的样子——所以上面的“童趣”代码是为了简化以确保我没有范围或处置问题。我有完整的异常记录,所以我知道这段代码在 OracleExceptions 开始之前不会抛出任何东西。所以具体来说,我同意你的看法,这是我开始的方式,这也是我希望我的代码在解决后看起来的方式,但目前不使用 using() 模式显然不是问题。 :|
【解决方案2】:

我知道这篇文章很旧,但几周前我遇到了同样的问题。即使在我的代码中插入“使用”语句后,错误仍然发生。直到我创建了一个更好的日志系统之后,我才意识到导致这个错误的异常是这样的:

ORA-01033: ORACLE 初始化或关机正在进行中

我找到的最佳解决方案是将此异常处理为休眠 5 分钟,以便预言机可以重新建立连接。


public void StartProcess()
{
    while(true) {
        try {
            //Everything the service does.
        }
        catch (Exception ex)
        {
              _serviceContainer.GetInstance<IErrorLogRepository>().Log(ex: ex);
              Thread.Sleep(300 * 1000);
         }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    相关资源
    最近更新 更多