Pull to refresh

Comments 21

В случае использования метода get_or_create() — написать свой метод, выполняющий принудительный COMMIT перед повторным чтением данных
тут следует учесть, что коммит приводит к глобальным изменениям. если клиентский код, использующий данный метод, помимо получения объекта, проводит с базой ещё какие-то манипуляции, то преждевременное подтверждение транзакции для него может стать чревато. в общем случае, коммитить транзакцию лучше на том же уровне, где её отрывали.
Согласен, но на самом деле в Django ORM любая операция изменения данных (create / update / delete) завершается принудительным COMMIT-ом, поэтому если программист использует в коде метод get_or_create(), то он должен быть готовым к тому, что в любом случае может быть произведен COMMIT для фиксации новосозданной записи, и все произведенные до этого незакоммиченные манипуляции будут тоже закоммичены. Поэтому в данном случае COMMIT перед SELECT-ом оправдан.
Но соглашусь, что перед использованием подобного рода методов, стоит осознавать что происходит в системе, и действовать НЕ наобум.
в Django ORM любая операция изменения данных (create / update / delete) завершается принудительным COMMIT-ом
Хм, странное поведение. В любом случае хардкод коммита после getorcreate это наихудшее из того, что можно придумать. Второй способ тоже не очень хорош, поскольку меняет глобальные настройки mysql. А если переезжать на другой сервер, настройки автокоммита перенести кто-нибудь да обязательно забудет. Так что единственным приемлемым решением является третий способ.
На дефолтном конфиге многое не вытянуть по производительности.
Не так давно налетели на эти грабли, помимо джанги БД использовалась rails приложением, долго понять не могли почему джанга не видет новые данные добавленные через рельсы. Изначально подумал что где то сидит кэш, но оказалось что проблема совсем иная, после чего наш гуру дал вводный курс по уровням изоляций транзакций =) Так что наматываем на ус и стараемся быть ниндзями, попутно хоть изучая базовые вещи использованных технологий, не всё же кирпичи ставить.
>Изначально подумал что где то сидит кэш
Да, я тоже когда первый раз столкнулся с подобной трабблой грешил на кэш. Особенно странно все это кажется после перехода с других языков, где для доступа к MySQL используются драйверы с AUTOCOMMIT=1, и все транзакции управляются вручную по мере необходимости.
А в чем приемущество использовать подход с ручным автокоммитом по-умолчанию?
С ручным автокоммитом — в смысле с AUTOCOMMIT=1 по умолчанию?
На мой взгляд транзакции нужны далеко не всегда — там где нужны, проще самому взять на себя управлением коммитами/роллбеками, а во всех остальных случаях использовать коммит по-умолчанию. Ошибочных ситуаций будет меньше — на подобии «забыл сделать коммит после какого-то select-а» и т.п.
Но это лишь мое мнение и оно не претендует на истину.
Вы пишите
1. В Django в качестве интерфейса к MySQL используется расширение MySQLdb, а оно в свою очередь при каждом подключении к базе устанавливает:
AUTOCOMMIT=0


Вот это я и имею ввиду под ручным автокоммитом. Хотел узнать какой в этом смысл?
Ммм… Это принято за аксиому в PEP 249 — Python Database API Specification v2.0:
Commit any pending transaction to the database. Note that if the database supports an auto-commit feature, this must be initially off. An interface method may be provided to turn it back on.

А вот почему — для меня тоже загадка.
Я также знаю, что Django ORM само заботится о внешних связях, т. е. делает это не на уровне БД как Doctrine ORM, а на уровне приложения.
Мне кажется это поведение неоправдонным в контексте целостности данных. Поправьте если я не прав.
Ммм… по поводу внешних связей — не могу сказать ничего плохого, т.к. багов на этом не ловил и сильно далеко в код Django не вкапывался на эту тему. Лично у меня syncdb при создании базы проставлял верно все внешние ключи. Но если у вас были с этим какие-то трабблы, то было бы интересно послушать.
Багов не ловил. Мало работал с Django.

Вот какая особенность. Миграции в БД создатели Django всецело переложили на плечи разработчиков. syncdb — лишь отслеживает новые таблицы, что годится для установки модулей (приложений в терминах Джанго) и соотв-но никак не годится для процесса разработки с изменением структуры БД. Но в тоже время они сами заботятся о целостности данных на уровне приложения (внешние связи, запросы с ручным автокоммитом). Вообщем, мне непонятна такая изберательность в подходе взаимодействия приложения с БД.
Для сравенения в Doctrine ORM (особенно во 2-й версии) отлично работает синхронизация структуры БД, описанной в конфиге/нотациях с реальной структурой БД. Также она не вмешивается в процесс целостности данных. Такой подход мне кажется более оправднонным и интуитивно понятным.
Если я правильно понял, мейнстрим-штуку для миграции данных South не включают в Джангу что бы не привязывать обновления South к обновлениям самой Джанги, т.к. первые могут быть гораздо чаще. А так эту батарейку используют многие другие батарейки.
Что-то я не пойму зачем коммитить перед чтением в обработке ошибки — если в таблице значение уже есть, то оно создавалось в другом месте или потоке и следовательно коммитить надо там.
в общем такие коммиты череваты волшебными багами, если есть управление транзакциями. А если коммитим каждую запись, то проще поднять автокоммит.
Второе чтение в последнем блоке try-except происходит только в случае если не удалось прочитать и создать данные, на случай если данные были уже созданы во временном промежутке между первоначальным чтением-созданием. В этом случае второй get будет всегда завершаться эррором, т.к. из-за AUTOCOMMIT=0 и REPEATABLE-READ новые данные не будут считаны из БД.
и как это исправит коммит в текущем потоке?
Самый true-way — в settings.py указать другой уровень изоляции транзакций при коннекте к БД, а именно READ COMMITTED
Извените, я подумал что это все в рамках READ COMMITED.
для REPEATABLE READ перед чтением надо делать коммит, согласен.
Sign up to leave a comment.

Articles