环境:postgres 9.6.3,npgsql 3.2.5,.net 4.5.1
我们执行导入/导出传输任务(大量数据逐行传输), 在读取期间使用游标和单独的连接来执行写入。
如果写操作需要一些时间(几秒钟),我们会在DataReader.Read()中收到以下错误:
Npgsql.NpgsqlException (0x80004005): Exception while reading from stream ---> System.IO.IOException:
Unable to read data from the transport connection:
An existing connection was forcibly closed by the remote host. --->
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at Npgsql.ReadBuffer.<Ensure>d__27.MoveNext()
at Npgsql.ReadBuffer.<Ensure>d__27.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Npgsql.NpgsqlConnector.<DoReadMessage>d__148.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
at Npgsql.NpgsqlConnector.<ReadMessage>d__147.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
at Npgsql.NpgsqlDataReader.<Read>d__28.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Npgsql.NpgsqlDataReader.Read()
根据暂停的持续时间(3-4秒),我们可以获取:120,240,......记录,以及异常提升。 如果我们不暂停读取,并且我们在一个循环中读取所有数据,它就可以工作。
由于空间分配原因,我们无法读取内存中的所有数据。我们看到收到的是: 在对DataReader.Read();
的失败调用期间发生DataReader_ReaderClosed事件这是我们的PG功能骨架:
CREATE FUNCTION "public"."myPGFunction" (INOUT cv_1 refcursor DEFAULT NULL::refcursor) RETURNS refcursor
AS $$
begin
OPEN cv_1 FOR
SELECT ....
FROM .... a;
end;
$$ LANGUAGE plpgsql
代码如下:
_Connection = new NpgsqlConnection("");
_Connection.Open();
_Transaction = _Connection.BeginTransaction();
_SelectCommand = _Connection.CreateCommand();
_SelectCommand.CommandText = "myPGFunction";
_SelectCommand.Connection = _Connection;
_SelectCommand.CommandType = CommandType.StoredProcedure;
NpgsqlParameter parCur = new NpgsqlParameter("cv_1".ToLower(), NpgsqlTypes.NpgsqlDbType.Refcursor);
parCur.Direction = ParameterDirection.InputOutput;
parCur.Value = "refcur";
_SelectCommand.Parameters.Add(parCur);
_SelectCommand.Transaction = _Transaction;
_SelectCommand.ExecuteNonQuery();
_SelectCommand.CommandText = "FETCH ALL IN \"refcur\"";
_SelectCommand.CommandType = CommandType.Text;
_DataReader = _SelectCommand.ExecuteReader();
这里是读取循环:
while(_DataReader.Read())
{
// Read Data
// Transfer data taking up to 3-4 seconds
...
}
使用CommandText =&#34; FETCH ALL IN \&#34; refcur \&#34;&#34 ;;在ExecuteReader()之后执行_DataReader.Read()循环是否有任何超时; ?
顺便说一句,我们测试了几个Command Timeout值,甚至是特殊的&#34;内部命令超时&#34;或TCP保持活力等... 对我们的问题没有任何影响。