2010-09-03 10 views
6

Moja aplikacja łączy się z wieloma bazami danych przy użyciu techniki podobnej do techniki this. Działa tak długo, dopóki nie próbuję uzyskać dostępu do różnych baz danych w tym samym żądaniu. Spojrzeliśmy z powrotem do powyższego skryptu widzę, że napisałem komentarz do tego celu:Jak mogę używać wielu baz danych w tym samym żądaniu w Cherrypy i SQLAlchemy?

SQLAlchemy integration for CherryPy, 
such that you can access multiple databases, 
but only one of these databases per request or thread. 

Moja aplikacja wymaga teraz mi się pobrać dane z bazy danych A i B. Czy to możliwe, aby zrobić to w jednym wniosku ?

podano poniżej źródeł i przykładach:

PRZYKŁAD WYKONANIA 1:

from model import meta 

my_object_instance = meta.main_session().query(MyObject).filter(
    MyObject.id == 1 
).one() 

Przykład roboczy 2:

from model import meta 

my_user = meta.user_session().query(User).filter(
    User.id == 1 
).one() 

błąd przykład:

from model import meta 

my_object_instance = meta.main_session().query(MyObject).filter(
    MyObject.id == 1 
).one() 

my_user = meta.user_session().query(User).filter(
    User.id == 1 
).one() 

Te błędy z:

(sqlalchemy.exc.ProgrammingError) (1146, "Table 'main_db.user' doesn't exist") 

Źródła:

# meta.py 
import cherrypy 
import sqlalchemy 
from sqlalchemy import MetaData 
from sqlalchemy.orm import scoped_session, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

# Return an Engine 
def create_engine(defaultschema = True, schema = "", **kwargs): 

    # A blank DB is the same as no DB so to specify a non-schema-specific connection just override with defaultschema = False 
    connectionString = 'mysql://%s:%[email protected]%s/%s?charset=utf8' % (
     store['application'].config['main']['database-server-config-username'], 
     store['application'].config['main']['database-server-config-password'], 
     store['application'].config['main']['database-server-config-host'], 
     store['application'].config['main']['database-server-config-defaultschema'] if defaultschema else schema 
    ) 
    # Create engine object. we pass **kwargs through so this call can be extended 
    return sqlalchemy.create_engine(connectionString, echo=True, pool_recycle=10, echo_pool=True, encoding='utf-8', **kwargs) 

# Engines 
main_engine = create_engine() 
user_engine = None 

# Sessions 
_main_session = None 
_user_session = None 

# Metadata 
main_metadata = MetaData() 
main_metadata.bind = main_engine 
user_metadata = MetaData() 

# No idea what bases are/do but nothing works without them 
main_base = declarative_base(metadata = main_metadata) 
user_base = declarative_base(metadata = user_metadata) 

# An easy collection of user database connections 
engines = {} 

# Each thread gets a session based on this object 
GlobalSession = scoped_session(sessionmaker(autoflush=True, autocommit=False, expire_on_commit=False)) 

def main_session(): 
    _main_session = cherrypy.request.main_dbsession 
    _main_session.configure(bind=main_engine) 

    return _main_session 

def user_session(): 
    _user_session = cherrypy.request.user_dbsession 
    _user_session.configure(bind = get_user_engine()) 

    return _user_session 

def get_user_engine(): 

    # Get dburi from the users instance 
    dburi = cherrypy.session['auth']['user'].instance.database 

    # Store this engine for future use 
    if dburi in engines: 
     engine = engines.get(dburi) 
    else: 
     engine = engines[dburi] = create_engine(defaultschema = False, schema = dburi) 

    # Return Engine 
    return engine 


def get_user_metadata(): 
    user_metadata.bind = get_user_engine() 
    return user_metadata 

# open a new session for the life of the request 
def open_dbsession(): 
    cherrypy.request.user_dbsession = cherrypy.thread_data.scoped_session_class 
    cherrypy.request.main_dbsession = cherrypy.thread_data.scoped_session_class 
    return 

# close the session for this request 
def close_dbsession(): 
    if hasattr(cherrypy.request, "user_dbsession"): 
     try: 
      cherrypy.request.user_dbsession.flush() 
      cherrypy.request.user_dbsession.remove() 
      del cherrypy.request.user_dbsession 
     except: 
      pass 
    if hasattr(cherrypy.request, "main_dbsession"): 
     try: 
      cherrypy.request.main_dbsession.flush() 
      cherrypy.request.main_dbsession.remove() 
      del cherrypy.request.main_dbsession 
     except: 
      pass 

    return 

# initialize the session factory class for the selected thread 
def connect(thread_index): 
    cherrypy.thread_data.scoped_session_class = scoped_session(sessionmaker(autoflush=True, autocommit=False)) 
    return 

# add the hooks to cherrypy 
cherrypy.tools.dbsession_open = cherrypy.Tool('on_start_resource', open_dbsession) 
cherrypy.tools.dbsession_close = cherrypy.Tool('on_end_resource', close_dbsession) 
cherrypy.engine.subscribe('start_thread', connect) 
+0

Nie chcę "odpowiadać" na moje własne pytanie, ale rozwiązaniem wydaje się być dodanie dodatkowej instrukcji scoped_session dla innej bazy danych w 'connect', więc wygląda na to' def connect (thread_index): cherrypy.thread_data.user_scoped_session_class = scoped_session (sessionmaker (autoflush = True, autocommit = False)) cherrypy.thread_data.main_scoped_session_class = scoped_session (sessionmaker (autoflush = True, autocommit = False)) zwraca ', a następnie odsyła je osobno w' open_dbsession' – OrganicPanda

Odpowiedz

1

Można również wybrać ORM, który został zaprojektowany od podstaw z myślą o wielu baz danych, takich jak Dejavu.

0

Spójrz na to:

http://pythonhosted.org/Flask-SQLAlchemy/binds.html

Zasadniczo, to sugeruje, że używasz param wiązania - dla każdego połączenia. To powiedziawszy, wydaje się, że to trochę hack.

To pytanie ma dużo więcej szczegółów odpowiedź:

With sqlalchemy how to dynamically bind to database engine on a per-request basis

powiedział, że zarówno to pytanie, a nie jeden odwołuje się najnowszy i sqlalchemy prawdopodobnie przeszły od tego czasu.

+0

To wygląda całkiem nieźle. Skończyło się na naprawieniu bezpośredniego problemu, z którym miałem do czynienia w związku z tym pytaniem (zobacz mój komentarz dołączony do pytania), ale skończyło się na kilku dalszych problemach; to wszystko działa teraz, ale kod i wyjaśnienie, które należy wykonać, są o wiele za duże dla StackOverflow. Wiele wątków + wiele dynamicznych połączeń DB na użytkownika + konfiguracja/odrywanie na żądanie = ból – OrganicPanda

Powiązane problemy