Является ли использование одноэлементного шаблона хорошей идеей при доступе к библиотекам с помощью MVC?

У меня есть веб-приложение, это приложение, как вы уже знаете, будет иметь много запросов, и каждый запрос будет выполняться в другом потоке, а это означает, что если я использую синглтон для доступа к моей библиотеке DAL, это не будет проблемой.

Однако я не уверен, что это лучший подход, потому что я читал, что в одном запросе я иногда использую разные потоки, и я также читал, что блокирующие потоки могут иногда приводить к потере производительности при использовании отдельных экземпляров.

Просто чтобы вы меня лучше поняли, вот что я планирую сделать:

DAL ‹- SingleInstance‹ - BAL ‹- SingleInstance‹ - Контроллеры ‹- Просмотры

Это хороший подход?

Это синглтон, который я планирую использовать:

     public static Products Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        class Nested
        {
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static Nested()
            {
            }

       internal static readonly Products instance = new Products();

Примечание. My Dal будет обращаться к базе данных с помощью ADO.NET (у меня есть причины использовать ado), а BAL будет использовать этот метод только для выполнения операций select или CRUD.

Мой код Ado.NET:

public static readonly string ConnectionString = @"Server=localhost;Database=test;Uid=root;Pwd=test;";

    public bool IsProduct(string name)
    {
        var conn = new SqlConnection(ConnectionString);
        bool result;
        try 
        {
            conn.Open();
            var command = new SqlCommand();
            SqlParameter[] parameters = new SqlParameter[1];
            parameters[0] = new SqlParameter("@Product", name);
            command.Connection = conn;
            command.CommandText = "SPC_GET_PRODUCT";
            command.CommandType = System.Data.CommandType.StoredProcedure;
            result = Convert.ToBoolean(command.ExecuteScalar());
        }
        finally 
        {
            conn.Close();
            conn.Dispose();
        }
        return result;
    }

Спасибо.


person user3044096    schedule 30.03.2015    source источник
comment
Мы понятия не имеем. Мы не видим, как реализован ваш DAL. Это Entity Framework? Находится ли он в собственном сервисе? Что делает ваш синглтон для доступа к DAL?   -  person Erik Funkenbusch    schedule 30.03.2015
comment
Обновил вопрос.   -  person user3044096    schedule 30.03.2015
comment
Это мало помогает и не отвечает ни на один из заданных мной вопросов.   -  person Erik Funkenbusch    schedule 30.03.2015
comment
Это Entity Framework? Нет, это ADO.NET. Что делает ваш синглтон для доступа к DAL? Products.Instance.GetProducts ();   -  person user3044096    schedule 30.03.2015
comment
А что делает GetProducts ()? именно этот код мы должны увидеть, является ли он потокобезопасным или нет.   -  person Erik Funkenbusch    schedule 30.03.2015
comment
Он выполняет все команды sqllcommand, sqlconnection, executeReader..etc и ado.net   -  person user3044096    schedule 30.03.2015
comment
Да, и КАК вы делаете этот код, важно и говорит нам, является ли он потокобезопасным ... отказ показать что-либо из этого означает, что мы не можем вам помочь.   -  person Erik Funkenbusch    schedule 30.03.2015
comment
Хорошо, опубликованный вами код является потокобезопасным, поскольку каждый вызов метода будет создавать новые экземпляры локальных объектов. Однако вам нужно быть осторожным, чтобы весь ваш код работал таким образом, и вы не используете какие-либо переменные-члены, которые могут вызвать условия гонки. Фактически, вы можете так же легко пометить этот метод как статический, что предотвратит случайное добавление переменной-члена.   -  person Erik Funkenbusch    schedule 30.03.2015
comment
И в этом отношении, если все ваши методы статичны (или могут быть статическими), то какая причина вам вообще нужна для синглтона? Вам вообще не нужен экземпляр класса.   -  person Erik Funkenbusch    schedule 30.03.2015


Ответы (1)


В общем, это, вероятно, не самая лучшая идея по нескольким причинам:

  • Синглтоны действительно сложно использовать с несколькими потоками для чего-либо сложного. Маловероятно, что большинство библиотек, в которые вы будете вызывать (например, Entity Framework), являются потокобезопасными, поэтому вам нужно будет выполнить множество блокировок для защиты ресурсов.

  • Вы почти наверняка пострадаете от ожидания блокировок с точки зрения производительности, а не от простого создания новых экземпляров уровня обслуживания. Нет смысла иметь полностью асинхронную платформу, если все ждут единственного контекста базы данных.

  • Их сложно модульное тестирование

  • Это семантически неверно. Под синглтоном подразумевается только один экземпляр класса. Не имеет смысла, что у вас будет работать только один экземпляр бизнес-логики в какой-то момент.

В синглтонах есть место для простых вещей, таких как доступ к данным конфигурации или создание экземпляра, которое действительно дорого. Но почти во всех других случаях есть способ лучше.

Есть другие ответы, объясняющие все проблемы с синглтоном.

person mfanto    schedule 30.03.2015
comment
Мой DAL будет с ADO.net - person user3044096; 30.03.2015
comment
ADO.net не является потокобезопасным. Вам нужно будет заблокировать доступ, пока один запрос сможет использовать базу данных. stackoverflow.com/questions/7316304/ - person mfanto; 30.03.2015
comment
Я знаю, но посмотрите на опубликованный мною код, он не использует блокировки и является потокобезопасным. - person user3044096; 30.03.2015
comment
Это только код для создания синглтона. Вам все равно нужно добавить свой код, когда он перестает быть потокобезопасным. В тот момент, когда у вас есть 2 запроса, выполните Products.Instance.Database или что-то еще, вы столкнетесь с ошибками. - person mfanto; 30.03.2015
comment
Я не понимаю, почему вы говорите, что это приведет к ошибкам, если это потокобезопасно. - person user3044096; 30.03.2015
comment
Я понимаю, о чем вы сейчас говорите, но мой код будет выполнять только sqlcommand, sql reader, я не понимаю, почему он выдает ошибку. - person user3044096; 30.03.2015
comment
Это не потокобезопасный. Все, что вам нужно сделать, это посмотреть на MSDN: msdn.microsoft.com/en-us/library/ Вы разместили статический конструктор. Это не имеет никакого отношения к тому, является ли ADO.net потокобезопасным. - person mfanto; 30.03.2015
comment
Если я правильно понимаю, даже если ADO.NET не является потокобезопасным, мой код Ado.net будет выполняться в том же потоке, что и экземпляр, поэтому я не понимаю, почему это проблема. - person user3044096; 30.03.2015
comment
Это не значит. Допустим, у вас есть 2 запроса к вашему сайту. Первый запрос будет выполняться в потоке 1, а второй запрос будет выполняться в потоке 2. Если оба потока вызовут Products.Instance.GetProducts (), то оба потока будут использовать одно и то же соединение SqlConnection, что не будет работать. - person mfanto; 30.03.2015
comment
Как они будут использовать одно и то же соединение sql, если я создам новое соединение для каждого метода? и каждый поток имеет свой отдельный метод? и каждый раз, когда я создаю новое соединение, пул соединений создает новое соединение? Смотрите код, который я только что опубликовал, потому что сейчас я запутался. - person user3044096; 30.03.2015
comment
Код, который вы опубликовали, в порядке, но в этом случае у вас будет много дублированной логики. - person mfanto; 30.03.2015
comment
Нет, это не так. Создание нового SqlConnection для каждого метода не улучшит производительность. stackoverflow.com/questions/1404261/ - person mfanto; 30.03.2015
comment
Я имею в виду, что производительность лучше, чем при использовании Entity Framework. - person user3044096; 30.03.2015
comment
@mfanto - URL-адрес, на который вы связались, явно говорит о пуле соединений и о том, как создание нового SqlConnection не требует больших затрат. - person Erik Funkenbusch; 30.03.2015
comment
Он может использовать пул соединений, но создание группы новых SqlConnection для обслуживания одного запроса по-прежнему будет хуже, чем использование одного экземпляра, поскольку то, что я собираюсь представить, не является реальной выгодой - person mfanto; 30.03.2015
comment
@mfanto - нет, если вам нужно заблокировать код для предотвращения многопоточного доступа. Шесть из одного, полдюжины из другого. - person Erik Funkenbusch; 30.03.2015
comment
Конечно, но поэтому я считаю, что этот шаблон в целом плохой. - person mfanto; 30.03.2015