Ответ 1
По пунктам.
1.
У меня есть устаревшая база данных, для которой я должен написать несколько утилит обработки данных. Использование шаблона Mapper без стиля ORM/ActiveRecord упростило для меня такие вещи, как запись запросов в ActiveRecord. Он работает с хорошими составными объектами, которые напоминают предложения SQL, защищенные от SQL-инъекций.
Объекты, являющиеся "пассивными", допускают большую гибкость/единообразие: результатом сложного объединения является именованный кортеж, как результат простого выбора. Там нет идентичности, о которой нужно заботиться, без кэшированных объектов с одинаковой идентичностью.
Все обновления явны; а не "сохранение" какого-либо состояния, измененного в другом месте, никаких крючков, работающих на .save()
и т.д. Это сделало эффективные пакетные обновления тривиальными, не беспокоя, если правильные данные отправляются в БД. Оба были преимуществами в моем случае. В общем случае "это зависит". Например, мне пришлось вручную извлекать идентификаторы, созданные с помощью базы данных, после вставки. Выполнение этого запроса явно является дополнительной работой. Возможность сделать это в одном запросе вместо одного на запись была огромным благом в моем случае.
SQLAlchemy имеет многоуровневый дизайн, который позволяет вам получить доступ к нижнему уровню "mapper", даже если вы объявляете вещи на верхнем уровне ORM и обычно работаете на нем. Например, в Django это не так просто, если/когда все еще возможно.
2.
В этом примере "репозиторий" выглядит как уровень, построенный над "mapper". Репозиторий мог быть построен поверх простого DBAPI, но картограф делает несколько простых вещей, таких как более удобное связывание параметров, именованные кортежи для наборов результатов, и обертка над простым SQL с составными, повторно используемыми частями.
Преобразователь также обеспечивает определенную степень независимости базы данных. Например. SQL Server и Postgres имеют разные способы конкатенации строк; mapper предоставляет унифицированный интерфейс.
3.
Вы пишете select
, где вы его используете. Если у вас есть выбор, который вы постоянно используете в разных контекстах, вы можете поместить его в метод или функцию. Большинство из них имеют одно использование и создаются на месте.
Хорошей особенностью дизайна SQLAlchemy является то, что вы можете легко сохранять условия и целые предложения where
и повторно использовать их в операторах select/update/delete.
4.
Question.query.filter_by(text = text).all()
использует неявную транзакцию.
db.session.query(Question).filter(Question.text == text).all()
использует явную транзакцию.
Явные транзакции дают вам спокойствие с DML. Они важны с помощью select
s, когда вы запрашиваете быстро меняющуюся базу данных и хотите, чтобы ваши несколько связанных select
отображали одно и то же согласованное состояние.
Обычно я пишу тривиальную оболочку вокруг sessionmaker
и пишу вещи так:
with my_database.transaction() as trans:
records = trans.query(...)
...
updated = trans.execute(...).rowcount
# Here the transaction commits if all went well.
Когда я определенно знаю, что DML не должен запускаться в этом блоке, я использую .readonly_transaction()
, который всегда откат.
Во многих случаях неявная транзакция прекрасна. Django позволяет вам украсить метод с помощью @transaction.atomic
и иметь полу-явное управление транзакциями, достаточное в 99% случаев. Но иногда вам нужна еще более тонкая гранулярность.