C# 在共享连接时正确重用SqlCommand和SqlParameter
我正在进行一个设置,其中一个可扩展的WCF服务组件连接到一个MS SQL Server数据库。RESTful服务允许用户将数据保存到数据库中并从中获取数据 在实现一个处理数据库连接/方法的类时,我开始努力正确地重用准备好的C# 在共享连接时正确重用SqlCommand和SqlParameter,c#,sql,sql-server,ado.net,C#,Sql,Sql Server,Ado.net,我正在进行一个设置,其中一个可扩展的WCF服务组件连接到一个MS SQL Server数据库。RESTful服务允许用户将数据保存到数据库中并从中获取数据 在实现一个处理数据库连接/方法的类时,我开始努力正确地重用准备好的SqlCommands和连接。我阅读了MSDN中有关连接池的内容,以及如何使用SqlCommand和SqlParameter 该类的初始版本如下所示: public class SqlRepository : IDisposable { private object s
SqlCommands
和连接。我阅读了MSDN中有关连接池的内容,以及如何使用SqlCommand
和SqlParameter
该类的初始版本如下所示:
public class SqlRepository : IDisposable
{
private object syncRoot = new object();
private SqlConnection connection;
private SqlCommand saveDataCommand;
private SqlCommand getDataCommand;
public SqlRepository(string connectionString)
{
// establish sql connection
connection = new SqlConnection(connectionString);
connection.Open();
// save data
saveDataCommand = new SqlCommand("INSERT INTO Table (Operation, CustomerId, Data, DataId, CreationDate, ExpirationDate) VALUES (@Operation, @CustomerId, @Data, @DataId, @CreationDate, @ExpirationDate)", connection);
saveDataCommand.Parameters.Add(new SqlParameter("Operation", SqlDbType.NVarChar, 20));
saveDataCommand.Parameters.Add(new SqlParameter("CustomerId", SqlDbType.NVarChar, 50));
saveDataCommand.Parameters.Add(new SqlParameter("Data", SqlDbType.NVarChar, 50));
saveDataCommand.Parameters.Add(new SqlParameter("DataId", SqlDbType.NVarChar, 50));
saveDataCommand.Parameters.Add(new SqlParameter("CreationDate", SqlDbType.DateTime));
saveDataCommand.Parameters.Add(new SqlParameter("ExpirationDate", SqlDbType.DateTime));
saveDataCommand.Prepare();
// get data
getTripCommand = new SqlCommand("SELECT TOP 1 Data FROM Table WHERE CustomerId = @CustomerId AND DataId = @DataId AND ExpirationDate > @ExpirationDate ORDER BY CreationDate DESC", connection);
getTripCommand.Parameters.Add(new SqlParameter("CustomerId", SqlDbType.NVarChar, 50));
getTripCommand.Parameters.Add(new SqlParameter("DataId", SqlDbType.NVarChar, 50));
getTripCommand.Parameters.Add(new SqlParameter("ExpirationDate", SqlDbType.DateTime));
getTripCommand.Prepare();
}
public void SaveData(string customerId, string dataId, string operation, string data, DateTime expirationDate)
{
lock (syncRoot)
{
saveDataCommand.Parameters["Operation"].Value = operation;
saveDataCommand.Parameters["CustomerId"].Value = customerId;
saveDataCommand.Parameters["CreationDate"].Value = DateTime.UtcNow;
saveDataCommand.Parameters["ExpirationDate"].Value = expirationDate;
saveDataCommand.Parameters["Data"].Value = data;
saveDataCommand.Parameters["DataId"].Value = dataId;
saveDataCommand.ExecuteNonQuery();
}
}
public string GetData(string customerId, string dataId)
{
lock (syncRoot)
{
getDataCommand.Parameters["CustomerId"].Value = customerId;
getDataCommand.Parameters["DataId"].Value = dataId;
getDataCommand.Parameters["ExpirationDate"].Value = DateTime.UtcNow;
using (var reader = getDataCommand.ExecuteReader())
{
if (reader.Read())
{
string data = reader.GetFieldValue<string>(0);
return data;
}
else
{
return null;
}
}
}
}
public void Dispose()
{
try
{
if (connection != null)
{
connection.Close();
connection.Dispose();
}
DisposeCommand(saveDataCommand);
DisposeCommand(getDataCommand);
}
catch { }
}
private void DisposeCommand(SqlCommand command)
{
try
{
command.Dispose();
}
catch (Exception)
{
}
}
}
公共类SqlRepository:IDisposable
{
私有对象syncRoot=新对象();
专用SqlConnection;
私有SqlCommand-saveDataCommand;
私有SqlCommand-getDataCommand;
公共SqlRepository(字符串连接字符串)
{
//建立sql连接
连接=新的SqlConnection(connectionString);
connection.Open();
//保存数据
saveDataCommand=new-SqlCommand(“插入表(操作、客户ID、数据、数据ID、CreationDate、ExpirationDate)值(@Operation、@CustomerId、@Data、@DataId、@CreationDate、@ExpirationDate)”,连接);
saveDataCommand.Parameters.Add(新的SqlParameter(“Operation”,SqlDbType.NVarChar,20));
saveDataCommand.Parameters.Add(新的SqlParameter(“CustomerId”,SqlDbType.NVarChar,50));
saveDataCommand.Parameters.Add(新的SqlParameter(“Data”,SqlDbType.NVarChar,50));
saveDataCommand.Parameters.Add(新的SqlParameter(“DataId”,SqlDbType.NVarChar,50));
saveDataCommand.Parameters.Add(新的SqlParameter(“CreationDate”,SqlDbType.DateTime));
saveDataCommand.Parameters.Add(新的SqlParameter(“ExpirationDate”,SqlDbType.DateTime));
saveDataCommand.Prepare();
//获取数据
getTripCommand=new SqlCommand(“从CustomerId=@CustomerId和DataId=@DataId和ExpirationDate>@ExpirationDate ORDER BY CreationDate DESC”连接的表中选择前1位数据);
添加(新的SqlParameter(“CustomerId”,SqlDbType.NVarChar,50));
添加(新的SqlParameter(“DataId”,SqlDbType.NVarChar,50));
添加(新的SqlParameter(“ExpirationDate”,SqlDbType.DateTime));
getTripCommand.Prepare();
}
public void SaveData(字符串customerId、字符串dataId、字符串操作、字符串数据、DateTime expirationDate)
{
锁定(同步根)
{
saveDataCommand.Parameters[“Operation”]。值=操作;
saveDataCommand.Parameters[“CustomerId”]。值=CustomerId;
saveDataCommand.Parameters[“CreationDate”]。Value=DateTime.UtcNow;
saveDataCommand.Parameters[“ExpirationDate”]。值=ExpirationDate;
saveDataCommand.Parameters[“Data”]。值=数据;
saveDataCommand.Parameters[“DataId”]。值=DataId;
saveDataCommand.ExecuteOnQuery();
}
}
公共字符串GetData(字符串customerId、字符串dataId)
{
锁定(同步根)
{
getDataCommand.Parameters[“CustomerId”]。值=CustomerId;
getDataCommand.Parameters[“DataId”]。值=DataId;
getDataCommand.Parameters[“ExpirationDate”]。值=DateTime.UtcNow;
使用(var reader=getDataCommand.ExecuteReader())
{
if(reader.Read())
{
字符串数据=reader.GetFieldValue(0);
返回数据;
}
其他的
{
返回null;
}
}
}
}
公共空间处置()
{
尝试
{
if(连接!=null)
{
connection.Close();
connection.Dispose();
}
DisposeCommand(saveDataCommand);
DisposeCommand(getDataCommand);
}
捕获{}
}
私有void DisposeCommand(SqlCommand)
{
尝试
{
command.Dispose();
}
捕获(例外)
{
}
}
}
有几个方面需要了解:
- 我正在使用
来加速执行命令的过程SqlCommand.Prepare()
- 重用这些命令可以避免在每次调用GetData和SaveData方法时创建新对象,从而不会导致垃圾收集器出现问题
- WCF服务只使用了
类的一个实例SqlRepository
- 这项服务每分钟有许多呼叫,因此我想要保持与DB的连接打开
using
语句中使用SqlConnection
对象以确保处理的事实。据我所知,连接池技术负责保持连接打开,即使using
语句调用了SqlConnection
的Dispose()
方法
使用这种方法的方法是在GetData
和SaveData
方法中使用(SqlConnection connection=newsqlconnection(connectionString))。然而,至少在我的直觉看来,我还需要在GetData
/SaveData
方法中创建SqlCommands。还是不?我找不到任何关于如何以这种方式重用命令的文档。如果每次进入GetData
/SaveData
方法时都需要准备一个新命令,那么对SqlCommand.Prepare()
的调用不是毫无意义吗
如何正确实现SqlRepository
类?现在的情况是,我相信如果连接中断(可能是因为DB服务器坏了)