2010-08-24 64 views
3

我正在为C#设计数据库包装。 下面是两个选择,我有:C#数据库包装设计

选项A:

class DBWrapper:IDisposable 
{ 
    private SqlConnection sqlConn; 

    public DBWrapper() 
    { 
      sqlConn = new SqlConnection("my connection string"); 
      sqlConn.Open(); 
    } 

    public DataTable RunQuery(string Sql) 
    { 
       implementation...... 
    } 

    public Dispose() 
    { 
      if(sqlConn != null) 
        sqlConn.Close(); 
    } 
} 

选项B:

class DBWrapper 
{ 
    public DBWrapper() 
    {    
    } 

    public DataTable RunQuery(string Sql) 
    { 
      SqlConnection sqlConn = new SqlConnection("my connection string"); 
      .....implementation...... 
      sqlConn.Close();    
    } 
} 

对于选项时,类实例化打开的连接。因此,无论调用者调用RunQuery多少次,连接总是准备就绪。但是,如果应用程序在应用程序的早期初始化DBWrapper,则连接将会刚刚打开,在应用程序完成之前什么也不做。另外,它可能会在执行过程中实例化许多DBWrapper。所以,这有点浪费资源。

对于选项B,它没有A选项的问题选项,但每次调用者调用RunQuery时都必须打开和关闭一个新连接。我不确定这会对表演造成多大的伤害。

请分享您的专业知识。谢谢你的阅读。

+1

他们往往会在这里得到一个坏名字,但有一个Singleton设计模式的阅读,这是我唯一一次使用单身人士 – acqu13sce 2010-08-24 05:56:01

+0

@ acqu13sce:为什么坏名字?模拟能力的原因是什么? – kbrimington 2010-08-24 06:00:29

+0

只是我通过阅读包括这个社区维基阅读一些评论http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons 我个人认为他们有他们的位置,但也许做被过度使用 – acqu13sce 2010-08-24 06:11:16

回答

6

出于性能考虑,你一定不希望与选项B去 让我建议选择C(至少在我所经历的情况。):

class DBWrapper:IDisposable { private SqlConnection sqlConn; 

public void EnsureConnectionIsOpen() 
{ 
    if (sqlConn == null) 
    { 
     sqlConn = new SqlConnection("my connection string"); 
     sqlConn.Open(); 
    } 

} 

public DataTable RunQuery(string Sql) 
{ 
    EnsureConnectionIsOpen(); 
    implementation...... 
} 

public Dispose() 
{ 
    if(sqlConn != null) 
       sqlConn.Close(); 
} 

} 

您可以考虑使用Singleton模式以确保只有一个DBWrapper实例。

+1

请注意,使用单例模式时,您可能会遇到一些有关多线程的问题(如果实现模式不正确)。虽然单身人士通常是这种类型的代码的良好解决方案,但在应用程序中使用静态应用程序时,应始终保持警觉并检查多线程问题。 – Gertjan 2010-08-24 06:03:33

+1

Singleton只是在线程之间共享对象的一种方式,但显然,只要您在线程之间共享对象,就必须仔细设计多线程,无论它们如何共享。 – Philipp 2010-08-24 06:08:42

+0

如果您在线程之间共享数据库连接(并且在用户之间的Web场景中),则可能会出现“有趣”的情况。它也将禁用你有多个连接。在父 - 子关系中收集数据时,有时需要多个连接,在这种情况下,当第一个连接用于收集父母时,您打开第二个连接以获取子项。 – Gertjan 2010-08-24 06:13:05

2

值得考虑的几点意见:

在你管理一个(也许)长期连接的方法,它来检查连接是否运行查询之前开放是非常重要的。一段时间之后,我遇到了.NETCF关闭未使用的连接之前的问题。

在您为每个查询打开一个新连接的方法中,确保您的连接,命令和(如果使用)数据读取器都使用语句正确包装或尝试/ finally + dispose()块以释放连接和锁。

快乐编码!

+0

谢谢您的提醒。 对于选项A,如果我确保我的类没有公开任何关闭连接的函数,并且总是有一个构造函数打开连接,那么应该没问题吧? 雅,我使用“使用”语句。 – Dreteh 2010-08-24 06:51:24

+0

@dreteh:我建议在使用前提供一个私人/受保护的财产来检查连接。类似'protected SqlConnection Connection {get {if(sqlConn.State == ConnectionState.Closed)sqlConn.Open();返回sqlConn; }}。作为一个免责声明,我从来没有遇到框架在紧凑框架之外关闭连接的问题。也许这个建议对于一个完整框架的应用程序来说是过分的。我会很好奇,看看连接是否会自动关闭进入待机或休眠状态的笔记本电脑。 – kbrimington 2010-08-24 11:12:41

1

选项B更具交易性,这是它的优势。 ADO.NET使用隐式连接池,因此您不必担心频繁创建SqlConnection的新实例。

您应该考虑是否使用连接或断开的数据模型;因为第二种方法更适合断开连接的模型。

但正如我上面所说的,连接池意味着它在实际应用上几乎没有区别。

+0

您的回答非常有用。 我正在考虑选项B,因为我想重载需要额外连接对象的RunQeury函数,这样我可以将几个数据访问器分组来实现事务(这样它们可以共享相同的连接)。我真正关心的唯一事情是不断打开和关闭连接可能效率不高。 – Dreteh 2010-08-24 07:02:20

0

您可以有一个选项C,其中数据库在RunQuery中请求时打开(如果未打开),并在处置(打开时)时关闭。这样数据库只在真正需要时才打开,并且只会打开一次。

因此,在伪代码:

class DBWrapper 
{ 

    public DBWrapper() 
    {    
    } 

    SqlConnection sqlConn = null; 

    public DataTable RunQuery(string Sql) 
    { 
      if(sqlConn == null) sqlConn = new SqlConnection("my connection string"); 
      .....implementation......    
    } 
    public Dispose() 
    { 
      if(sqlConn != null) 
        sqlConn.Close(); 
    } 

} 

而且记住,时刻调用Dispose并不总是直接后不需要再对象(例如一个函数变量使用该函数后)。据我所知,当垃圾收集器收集对象时(这不是直接的),它会被执行。但我对此并不完全确定。 Web和非Web应用程序之间的行为也可能不同。

+0

但是我可以看到这个设计也会有OptionA的问题,因为想象一下,如果RunQuery在执行开始时被调用,并且不会再被使用,直到结束。 – Dreteh 2010-08-24 06:54:36

+0

这是真的,但连接将在第一次需要时打开,而示例A在构建对象时打开。如果您希望收紧数据库的生命周期,则应手动关闭它,因为系统无法猜测您将来是否以及何时可能需要该数据库。 – Gertjan 2010-08-24 07:09:43

2

垃圾收集器在相当复杂的条件下被触发,但基本上当内存超过某个限制时被调用,它也被周期性地调用,但周期不是恒定的。你永远无法确定垃圾收集器的确切时间,并因此(在另一次运行中)破坏对象。有一件事你可以肯定的是,垃圾收集器永远不会处置和销毁仍然有引用的对象。例如,通过类上的静态变量引用的对象既不会被丢弃也不会被销毁。