c# - DAL和BO层Singleton的正确使用?

标签 c# .net design-patterns singleton

我的任务是为一个项目实现业务对象/数据访问层,并且必须同时处理成千上万的用户。 我一直使用单例来管理 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/Presentation 层:

User someUser = UserBO.GetInstance().GetUser(1);

这适用于我目前制作的应用程序,但我猜这是因为同时没有太多用户。 我担心当第二个用户请求某些东西但已经有第一个用户在其中执行一些繁重的操作时,UserDAL 实例中会发生什么。

我是否应该将此模式放在 BO/DAL 层中并仅将其保留在 ConnectionFactory 中?如果我使用它,我会遇到什么问题吗?

最佳答案

我肯定会完全放弃它,特别是对于连接:connectionFactory 可以是静态的,但每次被询问时都会返回一个新连接:ADO.NET 非常擅长管理连接池,你只需要离开就是这样。

在任何具有可变状态的事物中,请远离单例。这包括 ADO.NET 连接和您的实际业务对象。让一个用户改变另一个用户正在使用的对象的状态可能会导致各种奇怪的错误:在网站中,您基本上拥有一个大规模的多线程应用程序,而可变的单例是非常糟糕的消息!

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

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

悲观锁定表示所有可能更改的数据在读取时都会应用数据库锁,直到用户完成操作。这意味着保持交易开放,这对于网站来说是不切实际的。

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

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

关于c# - DAL和BO层Singleton的正确使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24287395/

相关文章:

c# - 如何遍历所有模型显示(名称=)属性值

c# - 尝试连接到 .sdf 数据库时出现异常

.net - .NET 资源文件仅用于本地化吗?

.net - 在没有序列化的情况下深度复制 .NET 类实例

SoA/AoS 内存布局的 C++ 零成本抽象

java - CompletableFuture : proper way to run a list of futures, 等待结果并处理异常

c# - asp.net 中的倒数计时器

c# - 为多个按钮注册一个点击事件并为每个按钮传递不同的值

.net - 通过身份验证自动从网站下载图片

c# - variable = null as "object destroying"是从哪里来的?