C# DAL和BO层中单态子的正确使用?

C# DAL和BO层中单态子的正确使用?,c#,.net,design-patterns,singleton,C#,.net,Design Patterns,Singleton,我的任务是为一个项目实现一个业务对象/数据访问层,同时需要数千名用户。 我一直使用单例来管理DAL,但我从来没有过多地考虑它将如何与这么多的多个用户同时使用,所以我想问一下它的正确用法 我有: public class UserDAL { private static UserDAL _userDAL = null; //Private constructor private UserDAL() { } public static UserDAL GetIn

我的任务是为一个项目实现一个业务对象/数据访问层,同时需要数千名用户。 我一直使用单例来管理DAL,但我从来没有过多地考虑它将如何与这么多的多个用户同时使用,所以我想问一下它的正确用法

我有:

public class UserDAL
{
    private static UserDAL _userDAL = null;

    //Private constructor 
    private UserDAL() { }

    public static UserDAL GetInstance()
    {
        if(_userDAL == null)
        { _userDAL = new UserDAL(); }

        return _userDAL;
    }

    //Example of a method
    public User GetUsers()
    {
        IDataReader dataReader = ConnectionFactory.GetConnection().ExecuteSomeQuery("queryHere");
    }
}
对于我的连接工厂,我不认为这是一个问题,尽管我确实读到最好将连接池留给ADO.NET本身:

public sealed class ConnectionFactory
{
    private static string _connectionString = ConfigurationManager.ConnectionStrings["ConnectionName"].ConnectionString;

    //My connection interface
    private static IConnection _connection = null;

    public static IConnection GetConnection()
    {
        if(_connection == null)
        {
            //some checks to determine the type
            _connection = new SQLConnection(_connectionString);
        }
        return _connection;
    }
}
我还在BO中使用单例模式,尽管我认为没有必要:

public class UserBO
{
    private static UserBO _userBO = null;
    private static UserDAL _userDAL = null;

    private UserBO() { }

    public static UserBO GetInstance()
    {
        if(_userBO == null)
        {
            _userBO = new UserBO();
            _userDAL = UserDAL.GetInstance();
        }

        return _userDAL;
    }

    //Example of a method
    public User GetUser()
    {
        //Rules
        return _userDAL.GetUsers();
        //return UserDAL.GetInstance().GetUsers(); //or this
    }
}
我这样做只是为了调用UI/表示层:

User someUser = UserBO.GetInstance().GetUser(1);
到目前为止,这对我开发的应用程序来说是有效的,但我猜这是因为没有太多的用户同时使用。 我担心当第二个用户请求某些内容,而第一个用户已经在其中执行一些繁重的操作时,UserDAL实例会发生什么情况


我是否应该将此模式放在BO/DAL层中,而只放在ConnectionFactory中?如果我使用它,会有什么问题吗?

我肯定会完全放弃它,特别是对于连接:connectionFactory可能是静态的,但每次被问到时都会返回一个新连接:ADO.NET非常擅长管理连接池,您只需避开它

在任何状态可变的情况下,远离单身汉。这包括ADO.NET连接和实际的业务对象。让一个用户改变另一个用户正在使用的对象的状态可能会导致各种奇怪的错误:在一个网站上,你基本上有一个大规模的多线程应用程序和可变的单例是非常坏的消息

不过,当两个或多个用户更改同一业务对象的副本时,您确实需要想出某种锁定策略。一个有效的策略包括说“事实上,这不会是一个问题,所以我会忽略它”——但前提是你已经考虑过了。两种基本策略是乐观锁定和悲观锁定

乐观锁定意味着您乐观地认为大多数用户不会更改相同的内容(无论出于何种原因),因此您不会对读取的数据设置数据库锁定。这是网站上唯一的可能性

悲观锁定表示,所有可能更改的数据在读取时都将应用DB锁,直到用户使用完为止。这意味着保持交易的开放性,这对于网站来说是不现实的

乐观锁定可以通过创建Update语句来实现,Update语句只在当前用户未更改的所有列在数据库中也未更改的情况下更新行;如果有,则其他人已更改同一行。或者,您可以向所有表中添加一列-
version int not null
,并在读取对象后版本未更改的位置进行更新;您还可以在每次更新中增加版本号


如果任何一种方法失败,您需要重新读取当前数据,并让用户确认或重新应用其更改。有点痛苦,但可能是必要的。

我建议您在可测试性方面远离单例模式:

相反,请看依赖项注入。这是一个很好的开始

DI将负责将BO和DAL连接在一起:

public interface IUserRepository
{
     IEnumerable<User> GetUsers();
}

public class UserBO
{
     private readonly IUserRepository _userRepository;

     public UserBO(IUserRepository userRepository){
         _userRepository = userRepository;
     }

     public IEnumerable<User> GetUsers()
     {
         return _userRepository.GetUsers();
     }
}
公共接口存储库
{
IEnumerable GetUsers();
}
公共类UserBO
{
专用只读IUserRepository\u userRepository;
公共UserBO(IUserRepository userRepository){
_userRepository=userRepository;
}
公共IEnumerable GetUsers()
{
返回_userRepository.GetUsers();
}
}

至于重用连接池:

我认为您误解了我的业务对象(或者我的理解是错误的),但这根本不是一个实体,它只是一个应用所有业务规则和所有调用的层。所以它应该返回实体的新实例(比如User),这样UserBO就没有任何状态。我肯定会为实体实施这个锁定策略,谢谢你的洞察力!是的,很抱歉。我以为BO是个商业目标。它看起来像是获取和更新/插入业务对象的包装器。只要它没有可改变的状态,那就没有问题。