哪个更好地处理对象?
Which is better to dispose the object?
如果是这种方法:
public void Delete(int id)
{
using (var connection = GetOpenConnection())
{
connection.Execute($"DELETE FROM MyTable WHERE Id = {id}");
}
}
或者只是:
GetOpenConnection().Execute($"DELETE FROM MyTable WHERE Id = {id}");
我想知道第二种是否是减轻维护和简化的最佳选择。
第一个选项为您提供可预测性:从 GetOpenConnection()
返回的连接对象将在 connection.Execute
完成后立即处理。
另一方面,如果您使用第二种方法,您可以希望连接在未来的某个时间关闭,但您完全不确定何时,即使它会发生.
因此,人们应该更喜欢第一种方法。
注意:考虑参数化您的查询。即使在您的情况下将 id
插入到查询中没有威胁,因为 id
的类型是 int
,但在整个代码中始终使用参数是个好主意。
回答这个问题需要了解 Sql 服务器(和其他数据库)如何使用连接,以及 ADO.Net 如何使用连接池。
数据库服务器往往一次只能处理有限数量的活动连接。它部分与系统上可用的有限 ephemeral ports 有关,但其他因素也可能起作用。这意味着重要的是要确保连接总是及时关闭,或者我们小心地限制连接的使用。如果我们希望数据库能够扩展到大量用户,我们必须两者兼顾。
.Net 以两种方式解决这种情况。首先,您用于数据库访问(System.Data
和公司)的 ADO.Net 库包含一个称为 连接池 的功能。此功能为您汇集和缓存连接,以便根据需要快速打开和关闭连接。该功能意味着 您不应该尝试在应用程序的生命周期内保持共享连接 object 处于活动状态,或者 session。 让连接池处理它,并创建大多数数据库访问的全新连接 object。
解决该问题的另一种方法是使用 IDisposable 模式。 IDisposable
通过 using
关键字在运行时提供直接支持的接口,这样您就可以确保 object 的非托管资源——就像您连接的数据库服务器上的临时端口holding on- 会以确定性的方式及时清理,即使抛出异常。此功能可确保您因连接池功能而创建的所有 short-lived 连接确实是它们需要的 short-lived。
换句话说,第一个示例中的 using 块起着重要作用。省略它是错误的。在繁忙的系统上,它甚至可能导致您的数据库出现拒绝服务的情况。
您可以从问题标题本身中了解到这一点,它会问,"Which is better to dispose the object?" 这两个样本中只有一个完全处理 object。
您可以采用这种方式进行设计。
using(var context = new CustomerFactory().Create())
return context.RetrieveAll();
然后在您的 CustomerContext
中,您将拥有处理逻辑、数据库连接和查询。但是您可以创建继承一个 DbConnectionManager
class,它将处理连接。但是整个 class 将被处理掉,这也将挽救连接管理器。
public interface ICustomerRepository : IDisposable
{
IEnumerable<Customer> RetrieveAll();
}
public interface ICustomerFactory
{
ICustomerRepository Create();
}
public class CustomerFactory : ICustomerFactory
{
public ICustomerRepository Create() => new CustomerContext();
}
public class CustomerContext : ICustomerRepository
{
public CustomerContext()
{
// Instantiate your connection manager here.
}
public IEnumerable<Customer> RetrieveAll() => dbConnection.Query<Customer>(...);
}
那就是如果你想打断一个富有表现力的调用,在选项二中代表你的流畅语法,而没有负面影响。
如果是这种方法:
public void Delete(int id)
{
using (var connection = GetOpenConnection())
{
connection.Execute($"DELETE FROM MyTable WHERE Id = {id}");
}
}
或者只是:
GetOpenConnection().Execute($"DELETE FROM MyTable WHERE Id = {id}");
我想知道第二种是否是减轻维护和简化的最佳选择。
第一个选项为您提供可预测性:从 GetOpenConnection()
返回的连接对象将在 connection.Execute
完成后立即处理。
另一方面,如果您使用第二种方法,您可以希望连接在未来的某个时间关闭,但您完全不确定何时,即使它会发生.
因此,人们应该更喜欢第一种方法。
注意:考虑参数化您的查询。即使在您的情况下将 id
插入到查询中没有威胁,因为 id
的类型是 int
,但在整个代码中始终使用参数是个好主意。
回答这个问题需要了解 Sql 服务器(和其他数据库)如何使用连接,以及 ADO.Net 如何使用连接池。
数据库服务器往往一次只能处理有限数量的活动连接。它部分与系统上可用的有限 ephemeral ports 有关,但其他因素也可能起作用。这意味着重要的是要确保连接总是及时关闭,或者我们小心地限制连接的使用。如果我们希望数据库能够扩展到大量用户,我们必须两者兼顾。
.Net 以两种方式解决这种情况。首先,您用于数据库访问(System.Data
和公司)的 ADO.Net 库包含一个称为 连接池 的功能。此功能为您汇集和缓存连接,以便根据需要快速打开和关闭连接。该功能意味着 您不应该尝试在应用程序的生命周期内保持共享连接 object 处于活动状态,或者 session。 让连接池处理它,并创建大多数数据库访问的全新连接 object。
解决该问题的另一种方法是使用 IDisposable 模式。 IDisposable
通过 using
关键字在运行时提供直接支持的接口,这样您就可以确保 object 的非托管资源——就像您连接的数据库服务器上的临时端口holding on- 会以确定性的方式及时清理,即使抛出异常。此功能可确保您因连接池功能而创建的所有 short-lived 连接确实是它们需要的 short-lived。
换句话说,第一个示例中的 using 块起着重要作用。省略它是错误的。在繁忙的系统上,它甚至可能导致您的数据库出现拒绝服务的情况。
您可以从问题标题本身中了解到这一点,它会问,"Which is better to dispose the object?" 这两个样本中只有一个完全处理 object。
您可以采用这种方式进行设计。
using(var context = new CustomerFactory().Create())
return context.RetrieveAll();
然后在您的 CustomerContext
中,您将拥有处理逻辑、数据库连接和查询。但是您可以创建继承一个 DbConnectionManager
class,它将处理连接。但是整个 class 将被处理掉,这也将挽救连接管理器。
public interface ICustomerRepository : IDisposable
{
IEnumerable<Customer> RetrieveAll();
}
public interface ICustomerFactory
{
ICustomerRepository Create();
}
public class CustomerFactory : ICustomerFactory
{
public ICustomerRepository Create() => new CustomerContext();
}
public class CustomerContext : ICustomerRepository
{
public CustomerContext()
{
// Instantiate your connection manager here.
}
public IEnumerable<Customer> RetrieveAll() => dbConnection.Query<Customer>(...);
}
那就是如果你想打断一个富有表现力的调用,在选项二中代表你的流畅语法,而没有负面影响。