2008-10-30 30 views
21

想知道是否建议将数据库连接对象(传递给其他模块)或让方法(在其他模块中)设置它。我倾向于让方法设置它,以便在使用它之前不必检查连接的状态,并且只需让调用方将所需的任何数据传递给调用方法,以便建立连接。将数据库连接对象传递给方法

回答

13

我个人喜欢用紧密范围连接;打开它们,使用它们并关闭它们(在“使用”块中,全部在本地方法中)。连接池将在大多数情况下处理重新使用连接,所以这种方法没有真正的开销。

传递连接使用的主要优势是,您可以传递事务;然而,TransactionScope是在方法之间共享事务的更简单的方式。

由于这些类是特定于实现的,我会写每个来打开它自己的本地事务。否则,您可以使用ado.net工厂方法从配置文件(提供程序名称)创建适当的类型。

1

我个人的工作是尽可能集中我的数据访问权限,但是,如果不行的话,我总是在其他类中打开一个新的连接,因为我发现有太多其他的东西可以阻挡传递实际的连接对象。

0

我会使用的web.config

<configuration> 
    <connectionStrings> 
     <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" /> 
     <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" /> 
    </connectionStrings> 
</configuration> 

然后你就可以在应用程序

+0

但我不想每片必须得到从配置,有1类mananages连接 – CSharpAtl 2008-10-30 20:24:38

+0

是否安全把连接字符串中的配置文件不加密? – 2014-11-02 07:20:26

1

设置连接从任何地方引用它是潜在的昂贵和潜在增加了一个往返。因此,再一次潜在地,更好的设计是传递连接对象。

我说可能,因为如果您是Microsoft ADO应用程序,你可能正在使用连接池....

+1

通常情况下,共同处理这个非常高兴......而不仅仅是为了网络。 – 2008-10-30 20:36:40

+0

好吧,我删除了单词“web” – 2008-10-30 20:42:40

8

对于自动化测试的目的,它通常是更容易的通过。这就是所谓的dependency injection

当您需要编写测试时,您可以创建一个模拟数据库连接对象,并传递该对象而不是真实的数据库连接对象。这样,您的自动化测试将不会依赖每次需要用数据重新填充数据的实际数据库。

+1

线程本地存储解决了这个没有在应用程序 – 2008-10-30 20:58:28

1

以下是对这个问题的更多了解。我有一个管理数据库连接的类,并有2个类来实现一个接口。其中一个类是SQL,另一个是OLAP。经理是知道要使用哪个连接的经理,因此它可以将确切的连接传递给类型,或者类型可以创建自己的连接。

1

您可以毫无问题地传递连接对象(例如,Microsoft Enterprise Library允许静态方法调用在连接中传递),或者您可以在外部管理它,直到您的设计为止,但没有直接的技术权衡。

小心的便携性不是通过一个特定的连接,如果您的解决方案将被移植到其他数据库(意思鸵鸟政策通过一个SqlConnection它打算与其他数据库工作)

9

个人而言,我喜欢使用SetData和GetData在Thread Local Storage的顶部存储我当前打开的连接和事务的堆栈。我定义了一个类来管理我与数据库的连接,并允许它使用dispose模式。这节省了我传递连接和事务的需求,这是我认为混乱和复杂的代码。

我强烈建议而不是让它保持每次需要数据时打开连接的方法。这将导致一个非常糟糕的情况,即在整个应用程序中都难以管理事务,并且打开和关闭了太多的连接(我知道连接池,从池中查找连接的代价比它更昂贵重用对象)

所以我最终不得不沿着这些线路(没有经过测试的东西):

class DatabaseContext : IDisposable { 

    List<DatabaseContext> currentContexts; 
    SqlConnection connection; 
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts) 
    { 
     currentContexts = contexts; 
     if (contexts.Count == 0) 
     { 
      connection = new SqlConnection(); // fill in info 
      connection.Open(); 
      first = true; 
     } 
     else 
     { 
      connection = contexts.First().connection; 
     } 

     contexts.Add(this); 
    } 

    static List<DatabaseContext> DatabaseContexts { 
     get 
     { 
      var contexts = CallContext.GetData("contexts") as List<DatabaseContext>; 
      if (contexts == null) 
      { 
       contexts = new List<DatabaseContext>(); 
       CallContext.SetData("contexts", contexts); 
      } 
      return contexts; 
     } 
    } 

    public static DatabaseContext GetOpenConnection() 
    { 
     return new DatabaseContext(DatabaseContexts); 
    } 


    public SqlCommand CreateCommand(string sql) 
    { 
     var cmd = new SqlCommand(sql); 
     cmd.Connection = connection; 
     return cmd; 
    } 

    public void Dispose() 
    { 
     if (first) 
     { 
      connection.Close(); 
     } 
     currentContexts.Remove(this); 
    } 
} 



void Test() 
{ 
    // connection is opened here 
    using (var ctx = DatabaseContext.GetOpenConnection()) 
    { 
     using (var cmd = ctx.CreateCommand("select 1")) 
     { 
      cmd.ExecuteNonQuery(); 
     } 

     Test2(); 
    } 
    // closed after dispose 
} 

void Test2() 
{ 
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection()) 
    { 
     using (var cmd = ctx.CreateCommand("select 2")) 
     { 
      cmd.ExecuteNonQuery(); 
     } 
    } 
    // leaves connection open 
} 
1

我建议你在连接对象和它的状态(开区分,关闭)。

你可以有一个单一的方法(或属性)读取web.config中的连接字符串。每次使用相同版本的连接字符串可确保您将从连接池中受益。

呼叫,当你需要打开一个连接该方法。在最后一刻,在设置完所有的SqlCommand属性后,打开连接,使用它,然后关闭它。在C#中,您可以使用using语句来确保连接已关闭。如果不是,请确保在finally块中关闭连接。