Ho un esempio di come farlo sul mio blog allo http://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/. Fondamentalmente è possibile migliorare la Session in modo che scelga da master o slave su una base query-per-query. Un potenziale problema con questo approccio è che se si ha una transazione che chiama sei query, si potrebbe finire per usare entrambi gli slave in una richiesta ... ma stiamo solo cercando di imitare la caratteristica di Django :)
A un po 'approccio meno magica che stabilisce anche l'ambito di utilizzo più esplicitamente che ho usato è un decoratore in vista callable (qualunque cosa si chiamano in Flask), in questo modo:
@with_slave
def my_view(...):
# ...
with_slave avrebbe fatto qualcosa di simile, presumendo che tu abbia una sessione e alcuni motori impostati:
master = create_engine("some DB")
slave = create_engine("some other DB")
Session = scoped_session(sessionmaker(bind=master))
def with_slave(fn):
def go(*arg, **kw):
s = Session(bind=slave)
return fn(*arg, **kw)
return go
L'idea è che chiamare Session(bind=slave)
invochi il registro per ottenere l'oggetto Session effettivo per il thread corrente, creandolo se non esiste, tuttavia dal momento che stiamo passando un argomento, scoped_session asserirà che la Sessione che stiamo fare qui è sicuramente nuovo di zecca.
Lo si punta sullo "slave" per tutti gli SQL successivi. Quindi, quando la richiesta è finita, assicurati che l'app Flask chiami lo Session.remove()
per cancellare il registro per quel thread. Quando il registro viene successivamente utilizzato sullo stesso thread, sarà una nuova sessione legata al "master".
o una sua variante, si desidera utilizzare lo "schiavo" solo per quella chiamata, questo è "più sicuro" in quanto ripristina qualsiasi legano esistente ritornare alla sessione:
def with_slave(fn):
def go(*arg, **kw):
s = Session()
oldbind = s.bind
s.bind = slave
try:
return fn(*arg, **kw)
finally:
s.bind = oldbind
return go
Per ognuno di questi decoratori puoi invertire le cose, avere la Sessione legata a uno "schiavo" in cui il decoratore lo mette in "master" per le operazioni di scrittura. Se si voleva uno slave casuale in quel caso, se Flask avesse un qualche tipo di evento "request begin" si poteva configurarlo in quel punto.
Thnx zzzeek Questo aiuta molto. Complimenti a tutto il fantastico lavoro su sqlalchemy. –
Rad commento, esempi di codice ottimo anche! Sarebbe bello se sqlalchemy avesse un modo per fare analisi delle query e instradare automaticamente, ma in un mondo in cui una query potrebbe causare una tabella tmp o un'altra operazione di scrittura come risultato di ciò che presumibilmente normalmente dovrebbe essere letto solo che richiederebbe qualcosa come la richiesta il piano di query dal back-end prima di inviare la query e sarebbe più problematico di quanto varrebbe nella maggior parte dei casi. –
abbiamo l'opzione "query analysis", sebbene richieda di scrivere da sé l'analisi. Il sistema orizzontale di sharding illustra un esempio di questo tipo di tecnica, vedi http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/horizontal_shard.html. – zzzeek