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

Я использовал много модели для подключения к БД, в моем последнем проекте, который я работал с C# & entity framework, я создал статический класс для подключения к БД, но у меня была проблема с открытием и закрытием соединения для этого дайте мне ошибку, когда более 10-15 запросов объединяются, я решил его с изменением метода подключения к БД с я подключаюсь сейчас по запросу и удалил все статические методы и классы.

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

что самая лучшая модель для делать связь?

  1. должен ли я закрывать его после каждого запроса и открывать его перед использованием или ...?
  2. соединение в статическом классе-хорошая модель (что мне не нужно создавать его каждый раз)?
  3. есть ли хороший шаблон дизайна для этой проблемы?
  4. все это для одного и того же вопроса, что является лучшим методом для подключение к базе данных (статическое, абстрактное, по запросу,...)?

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

  1. обновление одного sms доставлено или не доставлено
  2. Обновить баланс пользователя при поставке уменьшить баланс пользователя в таблице useraccounts
  3. номер обновления sms отправить счет в пользователя таблица
  4. обновить номер sms отправить счет в таблице мобильных номеров
  5. обновить количество sms отправить счет в таблице номер отправителя
  6. пакет обновления для доставленных и неудачных sms в таблице пакетов
  7. пакет обновления для того, как поток отправляет этот пакет в таблице пакетов
  8. обновить таблицу потоков для того, сколько sms отправить его этим протектором и сколько не удалось
  9. Добавить документ счета для этой операции в AccountDocument таблица

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

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

3 ответов


1. Should i close it after every query?

.Net делает это для вас, поэтому позвольте ему справиться с этим, это задача сборщика мусора. Поэтому не беспокойтесь о том, чтобы утилизировать свои объекты вручную, это хороший ответ Джона Скита:https://stackoverflow.com/a/1998600/544283. Однако вы можете использовать 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 инъекции зависимостей и единицы шаблонов работы велики, на самом деле entity framework is единица сама работа. 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 framework предоставляет EntityConnection через свойство Connection. Читайте как:public sealed class EntityConnection : DbConnection.

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

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

надеюсь, что это помогает.


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

  1. закрыть. .NET делает пул соединений для вас под капотом.

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

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

  4. каждого экземпляра.


вот мое предложение по архитектуре:

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

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

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

  4. каждое sms будет отправлено с помощью пользовательского threadpool на стороне службы windows.

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

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

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

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

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

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


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

обновление:

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

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

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