Как установить и управлять подключениями к базе данных в многомодульном приложении Python?

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

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

У меня есть модуль, определяющий класс объектов для пользователей. Он имеет множество определений для создания/удаления/обновления пользователей в базе данных. Модуль users.py импортируется в: а) консольную утилиту, 2) веб-приложение на основе web.py и 3) постоянно работающий процесс демона.

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

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

Я знаю, что каждая архитектура приложения отличается. Мне просто интересно, есть ли лучшая практика и что это будет?

Ответ 1

Лучший способ - открыть соединение, когда вам нужно выполнить некоторые операции (например, получение и/или обновление данных); манипулировать данными; запишите его обратно в базу данных в одном запросе (очень важно для производительности), а затем закройте соединение. Открытие соединения - довольно легкий процесс.

Некоторые ошибки для производительности включают

  • открытие базы данных, когда вы определенно не будете взаимодействовать с ней
  • с использованием селекторов, которые берут больше данных, чем вам нужно (например, получать данные обо всех пользователях и фильтровать их на Python, вместо того, чтобы просить MySQL отфильтровывать бесполезные данные)
  • записи значений, которые не изменились (например, обновление всех значений профиля пользователя, когда только их электронная почта была изменена)
  • с каждым полем обновлять сервер отдельно (например, открывать db, обновлять электронную почту пользователя, закрывать db, открывать db, обновлять пароль пользователя, закрывать db, открывать... вы получаете идею)

Суть в том, что неважно, сколько раз вы открываете базу данных, сколько запросов вы запускаете. Если вы можете заставить свой код присоединиться к связанным запросам, вы выиграли битву.

Ответ 2

Соединения MySQL относительно быстры, поэтому это может быть не проблема (т.е. вы должны измерить). Большинство других баз данных требуют гораздо больше ресурсов для создания соединения.

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

Если вы решите, что хотите сохранить соединение живым, чтобы его можно было повторно использовать, есть несколько моментов, о которых нужно знать:

  • Подключения, которые используются только для чтения, проще повторить, чем соединения, которые вы использовали для изменения данных базы данных.

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

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

Я лично рекомендовал бы против реализации вашего собственного алгоритма объединения пулов. Это очень трудно отлаживать, когда все идет не так. Вместо этого выберите библиотеку db, которая сделает это за вас.