Каков наилучший метод для подключения к базе данных (статический, абстрактный, для каждого запроса,...)?

Я использовал много модели для подключения к db, в моем последнем проекте, который я работал с С# и структурой сущности, я создал статический класс для подключения к db, но у меня была проблема с открытием и закрытием соединения, для чего я дал ошибку, когда больше, чем 10-15 запросов собрались вместе, я решил это с изменением метода подключения к db с я connect now per request и удалением всех статических методов и классов.

Теперь я хочу знать,

Что лучше всего подходит для подключения?

  • Должен ли я закрывать его после каждого запроса и открывать его перед использованием или...?
  • Соединение в статическом классе - хорошая модель (что мне не нужно создавать его каждый раз)?
  • Есть ли хороший шаблон для этой проблемы?
  • Все это по одному и тому же вопросу. Каков наилучший метод для подключение к базе данных (статические, абстрактные, для каждого запроса,...)?

Например,, работая на веб-панели отправителя sms, я должен отправлять 100 тыс. смс в секунду, эти sms собирать с другими и делать пакет, который у каждого пакета составляет 1 ~ 20 см, тогда мне нужно отправляйте пакеты 5K ~ 100K в секунду, и когда я отправляю пакет, я должен сделать следующие шаги:

  • Обновить один смс доставляемого или не доставленного
  • Обновление баланса пользователя при доставке уменьшает баланс пользователя в таблице useraccounts.
  • Обновить число отправленных смс в таблице пользователя
  • Обновить число отправленных смс в таблице мобильных номеров
  • Обновить число отправленных смс в таблице номеров отправителей.
  • Обновить пакет для доставленных и удаленных смс в таблице пакетов
  • Обновить пакет для того, как поток отправляет этот пакет в таблицу пакетов
  • Обновить таблицу потоков для того, сколько sms отправило ее этим протектором и сколько провалилось
  • Добавить документ учетной записи для этих транзакций в таблице AccountDocument

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

Теперь, что лучше всего подходит для подключения к БД? По запросу человека или по запросу потока или каждой отдельной транзакцией.

Ответ 1

1. Should i close it after every query?

.Net делает это для вас, поэтому пусть это обрабатывает, что задача сборщика мусора. Поэтому не беспокойтесь об утилизации своих объектов вручную, это хороший ответ от Jon Skeet: fooobar.com/questions/487223/.... Однако вы можете использовать оператор using(IDisposable){ }, чтобы заставить GC работать. Вот хорошая статья о перераспределении ресурсов: http://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About.

2. A connection in static class is good?

Никогда не создает статический контекст данных! Контексты данных не потокобезопасны или совместимы.

3. Is there a good design pattern for this problem?

Поскольку Belogix упоминает, что инъекция зависимостей и единичные шаблоны работы велики, на самом деле инфраструктура сущности - это единица работы. DI и UoW немного завышены, но это непросто реализовать, если вы впервые обрабатываете контейнер IoC, который, если вы идете по этому пути, я бы рекомендовал Ninject. Еще одна вещь: вам действительно не нужно DI, если вы не собираетесь запускать тесты, удивительность этих шаблонов заключается в том, чтобы разделиться, чтобы вы могли тестировать и издеваться над потоком.

In-short: Если вы собираетесь запустить тест против вашего кода, перейдите по этим шаблонам. Если нет, я предоставляю вам пример о том, как вы могли бы поделиться своим контекстом данных между службами, которые вы хотели бы. Это ответ на ваш четвертый вопрос.

4. What is the best method for making database connection (static, per request)?

Ваш контекстный сервис:

public class FooContextService {
    private readonly FooContext _ctx;

    public FooContext Context { get { return _ctx; } }

    public FooContextService() {
        _ctx = new FooContext();
    }
}

Другие услуги:

public class UnicornService {
    private readonly FooContext _ctx;

    public UnicornService(FooContextService contextService) {
        if (contextService == null)
            throw new ArgumentNullException("contextService");

        _ctx = contextService.Context;
    }

    public ICollection<Unicorn> GetList() {
        return _ctx.Unicorns.ToList();
    }
}

public class DragonService {
    private readonly FooContext _ctx;

    public DragonService(FooContextService contextService) {
        if (contextService == null)
            throw new ArgumentNullException("contextService");

        _ctx = contextService.Context;
    }

    public ICollection<Dragon> GetList() {
        return _ctx.Dragons.ToList();
    }
}

Контроллер:

public class FantasyController : Controller {
    private readonly FooContextService _contextService = new FooContextService();

    private readonly UnicornService _unicornService;
    private readonly DragonService _dragonService;

    public FantasyController() {
        _unicornService = new UnicornService(_contextService);
        _dragonService = new DragonService(_contextService);
    }

    // Controller actions
}

Вторые мысли (почти редактирование): Если вам нужен ваш контекст, чтобы не создавать прокси-серверы для ваших объектов, поэтому не имея ленивой загрузки, вы можете перегрузить вашу контекстную службу следующим образом:

public class FooContextService {
    private readonly FooContext _ctx;

    public FooContext Context { get { return _ctx; } }

    public FooContextService() : this(true) { }

    public FooContextService(bool proxyCreationEnabled) {
        _ctx = new FooContext();
        _ctx.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
    }
}

Примечание:

  • Если вы установили, что создание прокси включено в false, вы не будете иметь ленивую загрузку из коробки.
  • Если у вас есть контроллеры api, вы не хотите иметь дело с любым полным списком объектов.

EDIT:

Первое чтение:

Сделайте это:

(_context as IObjectContextAdapter).ObjectContext.Connection.Open();

Это отличная статья о Управление подключениями и транзакциями.

Структура Entity предоставляет EntityConnection через свойство Connection. Читайте как: public sealed class EntityConnection : DbConnection.

Соображения для управления соединениями: (взято из предыдущей ссылки)

  • Контекст объекта откроет соединение, если оно еще не открыто перед операцией. Если контекст объекта открывает соединение во время операции, он всегда будет закрывать соединение, когда операция будет завершена.
  • Если вы вручную откроете соединение, контекст объекта не закроет его. Вызов Закрыть или Dispose закроет соединение.
  • Если контекст объекта создает соединение, соединение всегда будет удаляться при размещении контекста.
  • В долгосрочном контексте объекта вы должны убедиться, что контекст расположен, когда он больше не требуется.

Надеюсь, что это поможет.

Ответ 2

отвечает на ваши вопросы:

  • Закройте его..NET делает пул соединений для вас под капотом.

  • Создайте его. используйте соединение (Connection conn = new....) каждый раз - таким образом, вы сможете максимально использовать механизм объединения .NET.

  • вы можете использовать .NET ThreadPool (или свой собственный пользовательский), определить ThreadPool, чтобы использовать только один поток в параллельном и рабочие элементы Enqueue один за другим. таким образом, не более 10 подключений будут использоваться в одно и то же время +, вероятно, это будет работать быстрее. Подробнее о Custom ThreadPools: Пользовательская реализация ThreadPool

  • В каждом экземпляре.


Здесь мое предложение для архитектуры:

  • Создайте таблицу базы данных (очередь) для отправки ожидающего сообщения.

  • каждая строка будет содержать всю информацию, необходимую для sms + текущего состояния.

  • создать рабочий процесс, возможно, службу Windows, которая будет отображать эту таблицу постоянно - пусть говорят, каждые 5 секунд. он выберет TOP ~ 20 SMS со статусом = ', ожидающим отправки' ​​(должен быть представлен как int). и обновит статус до "отправки"

  • каждый sms будет отправлен с использованием настраиваемого потока thread на стороне службы Windows.

  • В конце процесса ВСЕ обработанный статус sms будет обновлен до "done" с использованием CTE (общее табличное выражение - вы можете отправить cte со всеми идентификаторами строк sms, которые только что были обработаны выполните "массовое обновление" до состояния "done" ).

  • вы можете сделать хранимую процедуру обновления состояния той же, что и "getpending". таким образом, вы можете выбрать-для-обновления без блокировки и ускорить работу базы данных.

  • Таким образом, у вас может быть больше, чем только один процессор службы работает (но тогда вам придется потерять nolock).

помните, чтобы избежать как можно большей блокировки.

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

И еще одна вещь, я бы не рекомендовал использовать сущность framework для этого, поскольку он слишком много происходит под капотом. Все, что вам нужно для такого рода задач, - это просто вызвать 3-4 хранимых процедуры и это сделать. Возможно, посмотрите Dapper-dot-NET - это очень легкая инфраструктура MicroDal, которая в большинстве случаев работает более чем в 10 раз быстрее, чем EF (Entity Framework)

Ответ 3

Я думаю, что каждый запрос масштабирует лучшее. Используйте поточный пул соединений и объедините область соединения с единицей работы. Пусть служба, ответственная за транзакционное поведение и единицы работы, проверяет соединение, использует его и возвращает его в пул, когда единица работы либо совершена, либо отката.

UPDATE:

10-12 секунд, чтобы зафиксировать обновление статуса? Вы сделали что-то еще неправильно. Ваш вопрос, как написано, недостаточен для предоставления подходящего ответа.

Ежедневный объем NASDAQ - транзакции 1,3B, которые в течение 8 часов работают до ~ 45 тыс. транзакций в секунду. Ваш объем равен 2X от NASDAQ. Если вы пытаетесь сделать это с помощью одной машины, я бы сказал, что NASDAQ использует более одного сервера.

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