我有一个C#应用程序,可以跨多个函数和类进行许多SQL调用。该数据库是SQL Server 2008 R2。目前,每当需要向数据库读/写数据时,每个类或函数都会打开它自己的SQL连接:
using (SqlConnection connection = new SqlConnection(connectionString))
这是处理连接管理的正确方法吗?另外我只是开始添加事务,所以如果我没有弄错,应该在同一个连接上完成事务。以下是一些代码示例:
try
{
Class1 class1 = new Class1();
class1.data = "somedata";
class1.save(); // new sql connnection
Class2 class2 = new Class2();
class2.data = GetSomeData(); // new sql connection
class2.save(); // new sql connection
}
catch (Exception e)
{
}
我查看了TransactionScope和SqlTransaction,但我不确定我当前的连接结构是否适用于此实现。任何指导都将不胜感激。
答案 0 :(得分:4)
为每个操作“打开”一个新连接并不像人们想象的那样占用大量资源。
原因是今天所有ADO.NET提供商都在内部使用连接池。这意味着每次.Close()
连接时,它都会真正返回到池中。
当您开始在事务中涉及多个连接时,性能就会降低,因为这意味着事务被提升为分布式事务。也就是说,涉及第三方交易经理并控制交易。
所以答案是,只要您的实体没有依赖关系,就没有理由从事务开始或停止使用多个连接。
但是,如果实体A依赖于实体B,则必须使用交易。
依赖关系也可以由业务规则指定。我们来举个例子吧。
您有银行转帐,其中应从帐户A提取资金并存入帐户B.如果没有交易,可能会从帐户A中提取资金但不会存入B(由于错误)。
答案 1 :(得分:2)
您可以将两个保存调用括在启动事务的using子句中。
只要您的系统想要启动连接,它就会检查父事务是否存在。
http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx
结帐样本答案 2 :(得分:0)
至少创建一个处理对象持久性的数据访问类 - 只需将对象传递给知道如何处理它的类方法。如果类是一个孤立的实体(很可能不是这样的)(大多数对象与其他对象交互),那么在整个类中传播持久性代码才有意义。您应该使用.NET中可用的ORM功能 - SQLMetal(命令行)或Visual Studio中的LINQ-to-SQL ORM设计器。那么你就不会遇到你现在遇到的问题,而是可以专注于你真正试图用你的代码做的事情。
答案 3 :(得分:0)
是的,在同一代码块中使用using
子句,在对象和SQL服务器之间执行实际的数据封送是正确的方法。原因很简单,如果发生错误,那么您不会泄漏连接,这可能会导致其他非常难以找到问题。
问题在于您是否应该对每个单独的类进行save
调用,或者是否应该使用类似数据访问提供程序的东西来处理与数据库服务器的通信。
如果实体B依赖于实体A,意味着必须保存A并且在B可以正确保存之前返回ID,那么您可以选择。要么A需要引用B并处理它的保存,要么将两个对象都传递给处理正确保存的数据访问类。这里的一个例子是,如果实体A是订单头,而B是订单项。在这种情况下,A应该引用B的集合。当调用A.Save()
时,它应该迭代该集合并调用B.Save()
本身。
无论哪种方式都可以很容易地在单个连接的上下文中实现事务。