当我们将生产服务器从 12.5 升级到 15 时,我们遇到了一些在 .NET Framework 3.5 下运行并使用 Sybase.Data.AseClient.dll(版本 1.1.510.0)的代码的问题。在开发和测试环境中一切正常升级后,但在生产中失败,即使 ASP 经典代码和 PowerBuilder 代码能够调用生产 Sybase 服务器(大型遗留系统)。
如果我尝试为单个记录调用AseDataReader的Read方法,一切都很好。但是,如果我们允许读取所有记录,如果您通过 Sybase SQL Advandage 客户端调用存储过程,它将只读取将检索到的 67 条记录中的 22 条。我把它归结为一个玩具命令行应用程序来重现这个问题。以下是来自Read的错误详细信息:
Type: Sybase.Data.AseClient.AseException
Message: Internal Error: 30016
StackTrace: at Sybase.Data.AseClient.AseDataReader.?(Int32 A_0)
at Sybase.Data.AseClient.AseDataReader.?(Boolean A_0)
at Sybase.Data.AseClient.AseDataReader.?()
at Sybase.Data.AseClient.AseDataReader.Read()
at SybaseError.Program.TestCall(String friendlyName, String connectionString)
in C:\Projects\SybaseUpgradeError\SybaseError\Program.cs:line 42
假设您在using块中声明了IDataReader / AseDataReader ,当引发Read的原始错误时,当阅读器超出范围时,您实际上会收到以下错误:
Type: Sybase.Data.AseClient.AseException
Message: Internal Error: 30016
StackTrace: at Sybase.Data.AseClient.AseDataReader.?(Int32 A_0)
at Sybase.Data.AseClient.AseDataReader.?(Boolean A_0)
at Sybase.Data.AseClient.AseDataReader.?()
at Sybase.Data.AseClient.AseDataReader.?()
at Sybase.Data.AseClient.AseDataReader.?(Boolean A_0)
at Sybase.Data.AseClient.AseDataReader.NextResult()
at Sybase.Data.AseClient.AseDataReader.?()
at Sybase.Data.AseClient.AseDataReader.Close()
at Sybase.Data.AseClient.AseDataReader.?(Boolean A_0)
at Sybase.Data.AseClient.AseDataReader.Dispose()
at SybaseError.Program.TestCall(String friendlyName, String connectionString)
in C:\Projects\SybaseUpgradeError\SybaseError\Program.cs:line 54
您会注意到AseDataReader的Dispose方法正在引发异常,这是一个很大的禁忌。更糟糕的是,如果您将异常作为AseException 捕获并遍历Errors集合属性,则读取这些将引发异常。显然,检查AseError对象的属性实际上会调用属性中的一些动态代码,试图从活动连接中查找内容。这个版本的 Sybase .NET 客户端代码给我留下了深刻的印象。
问题归结为生产服务器上的数据包大小设置与开发和测试服务器上的不同。我没有管理员权限,但我相信它们在开发和测试服务器上设置为最小 2048 和最大 4096,但在生产服务器上最小和最大设置为 4096。这是基于我对电话会议的回忆,所以你的里程可能会有所不同。我只是想把它放在这里,以防以后对其他人有帮助。我们花了一段时间才找到问题所在。更改最小数据包大小并重新启动生产数据库服务器确实为我们解决了这个问题。
如果有帮助,这是我的测试控制台应用程序,其中连接字符串已被清除。同样,如果未注释,底部的注释行会引发错误。希望这对你有帮助!
using System;
using System.Data;
using Sybase.Data.AseClient;
namespace SybaseError
{
public class Program
{
public static void Main(string[] args)
{
const string DevelopmentConnection = "Data Source='**********';Port='****';UID='**********';PWD='**********';Database='**********';";
const string ReportConnection = "more secret stuff";
const string ProductionConnection = "yet more secret stuff";
TestCall("Development", DevelopmentConnection);
TestCall("Report", ReportConnection);
TestCall("Production", ProductionConnection);
Console.ReadKey();
}
private static void TestCall(string friendlyName, string connectionString)
{
Console.WriteLine("Calling procedure on " + friendlyName + ".");
int recordsRead = 0;
try
{
using (var connection = new AseConnection(connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
ConfigureCommand(command);
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
try
{
while (reader.Read())
{
// Would usually read things here...
recordsRead++;
}
}
catch (Exception exRead)
{
Console.WriteLine("Error on read:");
ShowError(exRead);
throw;
}
}
}
}
Console.WriteLine("Success calling procedure on " + friendlyName + ".");
}
catch (Exception ex)
{
Console.WriteLine("Outer error:");
ShowError(ex);
Console.WriteLine("Failure calling procedure on " + friendlyName + ".");
}
Console.WriteLine("Finished calling procedure on " + friendlyName + ". Read " + recordsRead + " records.");
Console.WriteLine(string.Empty);
}
private static void ConfigureCommand(AseCommand command)
{
command.CommandText = "sp_s_educator_route_tests";
command.CommandType = CommandType.StoredProcedure;
var spidParameter = new AseParameter("@spid", AseDbType.Integer);
spidParameter.Value = 1355945;
command.Parameters.Add(spidParameter);
var vendorIdParameter = new AseParameter("@vendor_id", AseDbType.Integer);
vendorIdParameter.Value = 1;
command.Parameters.Add(vendorIdParameter);
}
private static void ShowError(Exception ex)
{
Console.WriteLine("Type: " + ex.GetType());
Console.WriteLine("Message: " + ex.Message);
Console.WriteLine("StackTrace: " + ex.StackTrace);
var exAse = ex as AseException;
if (exAse != null)
{
//foreach (AseError error in exAse.Errors)
//{
// Console.WriteLine("SqlState: " + error.SqlState);
// Console.WriteLine("State: " + error.State);
//}
}
}
}
}