Я попытаюсь пролить некоторый свет на управление состоянием в SQLAlchemy, пройдя ваши пункты маркера.
- Сначала мы создадим пользователя
ed_user
и добавьте его в сессию.Его id
равно None
, поскольку строка не была записана в базу данных.
Перед добавлением вновь созданного объекта Ed в сеанс он находится в переходном процессе состояние;он не был добавлен в сеанс и не имеет идентификатора базы данных.Когда вы добавляете его в сеанс, он переходит в состояние в ожидании .Он не был сброшен в базу данных, но будет, когда произойдет следующая очистка.Если у вас включен autoflush (по умолчанию), все ожидающие изменения будут сброшены перед выполнением следующей операции запроса, чтобы убедиться, что состояния сеанса и базы данных синхронизируются при запросах, что приводит кнам:
- Затем мы создаем другого пользователя
our_user
, который получается путем запроса к базе данных запроса, который будет соответствовать ed_user
.Так что our_user
и ed_user
на самом деле один и тот же пользователь.
Сказать, что вы создаете our_user
, немного ошибочно.Вместо этого вы выполняете запрос и привязываете результат к имени our_user
:
>>> our_user = session.query(User).filter_by(name='ed').first()
Здесь важно помнить, что все ожидающие изменения сбрасываются до этот запрос имеет место.Это означает, что изменения, хранящиеся в объекте, связанном с именем ed_user
, отправляются в базу данных, и SQLAlchemy извлекает его идентификатор базы данных (id
больше не None
), переводя его в состояние persistent и добавив его в карту идентификации .
Поскольку все, что произошло за до запроса, вы получите строку, которая была создана, когда объект Ed был очищен какВ результате и проверяя идентичность этой строки (используя карту идентификаторов) SQLAlchemy замечает, что она фактически представляет существующий объект, содержащийся в сеансе, тот, который был связан с именем ed_user
ранее.Вот почему и ed_user.id
, и our_user.id
дают вам одинаковое значение - на самом деле ed_user is our_user
также будет True
;это один и тот же объект.
- Наконец, мы снова читаем значение
ed_user.id
, и база данных выдает запрос SELECT
, чтобы получить последнее значение id
так как предыдущий коммит завершил предыдущую транзакцию.
По умолчанию SQLAlchemy истекает все загруженное состояние базы данных после коммит , чтобы вы не могли работать с устаревшими данными.Некоторые другие потоки или процессы могли уже зафиксировать свои изменения между ними.Подобно большинству вещей, этим поведением можно управлять, передавая expire_on_commit=False
в sessionmaker
или Session
напрямую, если вам действительно нужно.