我们经常会讨论到数据访问超时的问题,当数据库服务器在远程,而且该操作需要耗用较长的时间的时侯,程序经常性出现一些超时的问题。那么应该从几个层面来探讨这个问题呢
1. 首先,我们来了解一下SQL Server内部执行的时间(默认是无限期等待的,即无超时)
2.其次,我们要知道SqlConnection的ConnectionTimeout属性,默认为15秒。这是获取在尝试建立连接时终止尝试并生成错误之前所等待的时间
该值不能通过编程设置,而是直接在连接字符串中指定
3.比较关键的是,我们要知道SqlCommand的CommandTimeout属性,默认为30秒。获取或设置在终止执行命令的尝试并生成错误之前的等待时间
值 0 指示无限制,在 CommandTimeout 中应避免值 0,否则会无限期地等待执行命令
此属性是在执行命令或处理结果期间所有网络读取的累积超时。在返回第一行之后,超时仍然可能发生,但只包括网络读取时间,而不包括用户处理时间。
结合这三点,我做了一个例子。下面的存储过程是故意地阻塞2分钟。
CREATE PROC GetServerTime(@result DATETIME OUTPUT)
AS
WAITFOR DELAY '00:02:00'
SET @result=getdate()
下面是客户端代码
using System;
using System.Data.SqlClient;
using System.Data;
namespace Test
{
class Program
{
static void Main(string[] args)
{
SqlConnection conn = null;
try
{
using (conn = new SqlConnection("server=(local);database=northwind;integrated security=true;connection timeout=30"))
{
//Console.WriteLine(conn.ConnectionTimeout.ToString());
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandTimeout = 0;//这里设置为0,即取消了命令的超时限制
cmd.CommandText = "GetServerTime";
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("@result", SqlDbType.DateTime);
param.Direction = ParameterDirection.Output;
cmd.Parameters.Add(param);
Console.WriteLine("开始工作:" + DateTime.Now.ToString());
cmd.ExecuteNonQuery();
Console.WriteLine("取得结果:"+param.Value.ToString());
}
conn.Close();
}
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (conn != null && conn.State != ConnectionState.Closed)
conn.Close();
}
Console.Read();
}
}
}
4.当该代码放在中间层,我们这里用Web Service为例,看看是否有什么问题?
using System.ComponentModel;
using System.Data;
using System.Web.Services;
using System.Data.SqlClient;
namespace WebService1
{
///
/// Service1 的摘要说明
///
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string GetServerTime()
{
SqlConnection conn = null;
string result = string.Empty;
try
{
using (conn = new SqlConnection("server=(local);database=northwind;integrated security=true;connection timeout=30"))
{
//Console.WriteLine(conn.ConnectionTimeout.ToString());
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandTimeout = 0;
cmd.CommandText = "GetServerTime";
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("@result", SqlDbType.DateTime);
param.Direction = ParameterDirection.Output;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
result= param.Value.ToString();
}
conn.Close();
}
}
catch (SqlException ex)
{
throw ex;
}
finally
{
if (conn != null && conn.State != ConnectionState.Closed)
conn.Close();
}
return result;
}
}
}
我们用客户端调用该web server,但仍然会超时。同样的代码,为什么会产生不一样的结果呢?
还要注意的一个地方是调用web service的客户端代理的超时设置。准确地说,大部分web service的代理类都是继承自WebClientProtocol类的。这个类有一个属性:timeout
http://msdn.microsoft.com/zh-cn/library/system.web.services.protocols.webclientprotocol.timeout.aspx
指示 XML Web services 客户端等待同步 XML Web services 请求完成的时间(以毫秒计)。默认值为 100000 毫秒。(即100秒)
如果将 Timeout 属性设置为 Timeout..::.Infinite,则指示该请求无超时。即使 XML Web services 客户端可以将 Timeout 属性设置为无超时,Web 服务器仍可以在服务器端使请求超时
ASP.NET的程序默认的执行超时时间为110秒,这是通过web.config文件中的一个属性设置的。就是下面这个executionTimeout.单位为秒,默认为110.以前是90.
注意,该属性只有当debug=false才生效