2012-08-31 33 views
59

Sadece hızlı bir soru: SQLAlchemy talks about arama sessionmaker() bir kez ama DB ile konuşmanız gereken her zaman ortaya çıkan Session() sınıfı çağırıyor. Benim için o yapardım ikinci anlamı benim ilk session.add(x) veya benzeri bir şey, ben ilk yapacağını şimdi benim modelinde çağrı session = Session() yapmaktı kadar YaptıklarımıSQLAlchemy: Bir oturumu yeniden oluşturma vs oluşturma

from project import Session 
session = Session() 

kez ve sonra hep aynı içe Uygulamamda herhangi bir yerde oturum açın. Bu bir web uygulamaları olduğundan, bu genellikle aynıdır (bir görünüm yürütüldüğünde).

Fakat fark nerede? Benim fonksiyonum bitene kadar benim veritabanı şeylerim için her zaman bir seans kullanmanın dezavantajı ve daha sonra DB'mle konuşmak istediğimde yeni bir tane yaratmanın dezavantajı nedir?

Birden çok iş parçacığı kullanırsam, her birinin kendi oturumunu alması gerekir. Ama scoped_session() kullanarak, zaten sorunun mevcut olmadığından emin oluyorum, değil mi?

Lütfen varsayımlarımın yanlış olup olmadığını açıklayın.

cevap

152

sessionmaker(), bir fabrikada, yalnızca Session nesnesini oluşturmak için yapılandırma seçeneklerini tek bir yere yerleştirmeye teşvik etmek için var. İsteğe bağlı olarak, Session nolu yeni bir Session numaralı telefona ihtiyaç duyduğunuzda istediğiniz kadar kolay bir şekilde arayabilmeniz için isteğe bağlı ve gereksizdir ve her biri bu fazlalık sorununa yaklaşan küçük ölçekli "yardımcıların" çoğalmasını durdurmak istedim. bazı yeni ve daha kafa karıştırıcı bir yol.

sessionmaker() Bu nedenle, gereksinim duyduğunuzda Session nesnesi oluşturmanıza yardımcı olacak bir araçtır.

Sonraki parça. Bence soru şu ki, yeni bir Session()'u çeşitli noktalarda yapmanın arasındaki fark nedir? Cevap, çok değil. Session, içine koyduğunuz tüm nesneler için bir kapsayıcıdır ve daha sonra açık bir işlemin kaydını tutar. Şu anda, rollback() veya commit() numaralı telefonu aradığınızda, işlem bitti ve Session, SQL'i yeniden yayımlamak için çağrılana kadar veritabanına bağlantı içermiyor. Eşlenmiş nesnelerinizde tuttuğu bağlantılar zayıf referanslardır, nesneler bekleyen değişikliklerin temiz olması şartıyla, Session bu uygulamada bile, uygulamanız eşlenmiş nesnelerdeki tüm başvuruları kaybettiğinde yepyeni bir duruma dönecektir. Varsayılan "expire_on_commit" ayarıyla bırakırsanız, tüm nesnelerin bir taahhüt işleminden sonra sona ermektedir. Bu Session beş ya da yirmi dakika boyunca takılırsa ve veritabanını her kullandığınızda her türlü şey değiştiyse, oturmuş olsalar bile bu nesnelere bir daha eriştiğinizde tüm yeni durumu yükler. yirmi dakika boyunca hafıza.

Web uygulamalarında genellikle diyoruz, hey aynısını tekrar tekrar kullanmak yerine, her istekte yepyeni bir Session yapmıyorsunuz. Bu uygulama, yeni talebin "temiz" yapılmasını sağlar. Eğer önceki taleplerden bazı nesneler henüz çöp toplanmamışsa ve belki de "expire_on_commit"'u kapatmış olsaydınız, önceki isteğin bir kısmı hala etrafta asılı kalır ve bu durum oldukça eski olabilir. expire_on_commit açık bırakmak ve kesinlikle istek üzerine commit() veya rollback()'u aramak için dikkatli iseniz, o zaman bu iyi, ancak bir Session yepyeni ile başlarsanız, o zaman temizlemeye başladığınız herhangi bir soru bile yok.Bu nedenle, yeni bir Session ile her isteği başlatma fikri, yeni başladığınızdan emin olmanın en basit yoludur ve expire_on_commit kullanımını oldukça isteğe bağlı hale getirmektedir, çünkü bu bayrak bir işlem için çok fazla SQL gerektirebilir Bu, bir dizi işlemin ortasında commit()'u çağırır. Bu, sorunuza cevap verip vermediğinden emin değil.

Sonraki aşama, iş parçacığı hakkında bahsettiğiniz şeydir. Uygulamanız çok iş parçacıklıysa, kullanımda olan Session öğesinin yerel bir şey olduğundan emin olmanızı öneririz. scoped_session() varsayılan olarak geçerli iş parçacığına yerel yapar. Bir web uygulamasında, isteğin yerel olması aslında daha da iyidir. Flask-SQLAlchemy aslında bir özel "kapsam işlevi" scoped_session() gönderir, böylece isteğe bağlı bir oturum alırsınız. Ortalama Piramit uygulaması, Oturumu "istek" kayıt defterine yapıştıracaktır. Bu gibi şemaları kullanırken, "istek üzerine yeni bir oturum oluştur" fikri, işleri düz tutmanın en basit yolu gibi görünmeye devam ediyor. Mükemmel zzzeek cevabı ek olarak

+9

Wow, bu SQLAlchemy bölümündeki tüm sorularımı yanıtlar ve hatta Flask hakkında bazı bilgiler ekler. nd Piramidi! Eklenen bonus: geliştiriciler cevap;) Keşke bir kereden fazla oy verebilseydim. Çok teşekkür ederim! – javex

+0

Mümkünse bir açıklama: Eğer expire_on_commit "fazladan bir çok SQL katılabilir" diyorsunuz ... daha fazla detay verebilir misiniz? Expire_on_commit'in sadece RAM'da ne olduğunu, veritabanında ne olduğunu düşünmediğini düşündüm. – Veky

+2

expire_on_commit aynı Session'ı tekrar kullanırsanız, daha fazla SQL ile sonuçlanabilir ve bu oturumda bazı nesneler hala bu oturumda takılır, bunlara eriştiğinizde her biri için tek tek SELECT seçersiniz. Durumunu yeni işlem açısından yenilemek. – zzzeek

12

, burada hızlı bir ıskarta, kendinden kapalı oturumları oluşturmak için basit tarifi:

from contextlib import contextmanager 

from sqlalchemy import create_engine 
from sqlalchemy.orm import scoped_session, sessionmaker 

@contextmanager 
def db_session(db_url): 
    """ Creates a context with an open SQLAlchemy session. 
    """ 
    engine = create_engine(db_url, convert_unicode=True) 
    connection = engine.connect() 
    db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine)) 
    yield db_session 
    db_session.close() 
    connection.close() 

Kullanımı: Sen db kullanarak oturumu oluşturabilir

from mymodels import Foo 

with db_session("sqlite://") as db: 
    foos = db.query(Foo).all() 
+0

Sadece yeni bir oturum değil, aynı zamanda yeni bir bağlantı oluşturmanın bir nedeni var mı? – aforaudrey

+0

Gerçekten değil - bu, bu yaklaşımı en çok kullandığım testte taze olan her şeyi yaratmanın anlamlı olmasına rağmen, mekanizmayı göstermek için hızlı bir örnektir. Bu işlevi isteğe bağlı argüman olarak bağlantı ile genişletmek kolay olmalıdır. –

-1

+3

, 'Flask'a özgü,' SQLAlchemy' değil yaygındır –

İlgili konular