Наскільки я знаю, немає способу змусити ОРМ видавати масові вставки. Я вважаю, що основна причина полягає в тому, що SQLAlchemy потребує відстеження ідентичності кожного об'єкта (тобто, нових первинних ключів), і масові вставки перешкоджають цьому. Наприклад, якщо припустити, що ваша foo
таблиця містить id
стовпець і відображена у Foo
класі:
x = Foo(bar=1)
print x.id
# None
session.add(x)
session.flush()
# BEGIN
# INSERT INTO foo (bar) VALUES(1)
# COMMIT
print x.id
# 1
Оскільки SQLAlchemy зібрав значення для, x.id
не видаючи іншого запиту, ми можемо зробити висновок, що воно отримало значення безпосередньо з INSERT
заяви. Якщо вам не потрібен наступний доступ до створених об'єктів через ті самі екземпляри, ви можете пропустити рівень ORM для своєї вставки:
Foo.__table__.insert().execute([{'bar': 1}, {'bar': 2}, {'bar': 3}])
# INSERT INTO foo (bar) VALUES ((1,), (2,), (3,))
SQLAlchemy не може співставити ці нові рядки з будь-якими існуючими об'єктами, тому вам доведеться запитувати їх заново для будь-яких наступних операцій.
Що стосується застарілих даних, то корисно пам’ятати, що сеанс не має вбудованого способу знати, коли база даних змінюється поза сеансом. Щоб отримати доступ до зовнішньо модифікованих даних через існуючі екземпляри, екземпляри повинні бути позначені як закінчені . Це відбувається за замовчуванням на session.commit()
, але можна зробити вручну з допомогою виклику session.expire_all()
або session.expire(instance)
. Приклад (SQL опущено):
x = Foo(bar=1)
session.add(x)
session.commit()
print x.bar
# 1
foo.update().execute(bar=42)
print x.bar
# 1
session.expire(x)
print x.bar
# 42
session.commit()
термін дії закінчується x
, тому перше твердження про друк неявно відкриває нову транзакцію та повторно запитує x
атрибути. Якщо ви коментуєте перше твердження про друк, ви помітите, що друге тепер набирає правильне значення, оскільки новий запит не надсилається до моменту оновлення.
Це має сенс з точки зору транзакційної ізоляції - вам слід підбирати лише зовнішні модифікації між транзакціями. Якщо це спричиняє вам проблеми, я б радив уточнити або переосмислити межі транзакцій вашої програми, а не негайно звертатися до них session.expire_all()
.