Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Aplikacje Django dla wielu dzierżawców:zmiana połączenia z bazą danych na żądanie?

Zrobiłem coś podobnego, co jest najbliższe punktowi 1, ale zamiast używać oprogramowania pośredniczącego do ustawienia domyślnego połączenia, używane są routery bazodanowe Django. Dzięki temu logika aplikacji może korzystać z wielu baz danych, jeśli jest to wymagane dla każdego żądania. Wybór odpowiedniej bazy danych dla każdego zapytania zależy od logiki aplikacji i to jest duży minus tego podejścia.

W tej konfiguracji wszystkie bazy danych są wymienione w settings.DATABASES , w tym bazy danych, które mogą być udostępniane klientom. Każdy model, który jest specyficzny dla klienta, jest umieszczany w aplikacji Django, która ma określoną etykietę aplikacji.

np. Poniższa klasa definiuje model, który istnieje we wszystkich bazach danych klientów.

class MyModel(Model):
    ....
    class Meta:
        app_label = 'customer_records'
        managed = False

Router bazy danych znajduje się w settings.DATABASE_ROUTERS łańcuch do kierowania żądania bazy danych przez app_label , coś takiego (nie pełny przykład):

class AppLabelRouter(object):
    def get_customer_db(self, model):
        # Route models belonging to 'myapp' to the 'shared_db' database, irrespective
        # of customer.
        if model._meta.app_label == 'myapp':
            return 'shared_db'
        if model._meta.app_label == 'customer_records':
            customer_db = thread_local_data.current_customer_db()
            if customer_db is not None:
                return customer_db

            raise Exception("No customer database selected")
        return None

    def db_for_read(self, model, **hints):
        return self.get_customer_db(model, **hints)

    def db_for_write(self, model, **hints):
        return self.get_customer_db(model, **hints)

Specjalną częścią tego routera jest thread_local_data.current_customer_db() połączenie. Przed uruchomieniem routera wywołujący/aplikacja musi skonfigurować bieżącą bazę danych klienta w thread_local_data . W tym celu można użyć menedżera kontekstu Pythona do push/pop aktualnej bazy danych klientów.

Po skonfigurowaniu tego wszystkiego kod aplikacji wygląda mniej więcej tak, gdzie UseCustomerDatabase jest menedżerem kontekstu, który wpycha/przeskakuje bieżącą nazwę bazy danych klientów do thread_local_data aby thread_local_data.current_customer_db() zwróci poprawną nazwę bazy danych, gdy router zostanie w końcu trafiony:

class MyView(DetailView):
    def get_object(self):
        db_name = determine_customer_db_to_use(self.request) 
        with UseCustomerDatabase(db_name):
            return MyModel.object.get(pk=1)

To już dość skomplikowana konfiguracja. To działa, ale spróbuję podsumować to, co widzę jako zalety i wady:

Zalety

  • Wybór bazy danych jest elastyczny. Pozwala na użycie wielu baz danych w jednym zapytaniu, zarówno specyficzne dla klienta, jak i współdzielone bazy danych mogą być używane w żądaniu.
  • Wybór bazy danych jest jawny (nie jestem pewien, czy jest to zaleta czy wada). Jeśli spróbujesz uruchomić zapytanie, które trafi do bazy danych klientów, ale aplikacja nie wybrała żadnego, wystąpi wyjątek wskazujący na błąd programowania.
  • Korzystanie z routera baz danych pozwala na istnienie różnych baz danych na różnych hostach, zamiast polegać na USE db; stwierdzenie, które zgaduje, że wszystkie bazy danych są dostępne za pośrednictwem jednego połączenia.

Wady

  • Konfiguracja jest skomplikowana i jest wiele warstw zaangażowanych w jej działanie.
  • Potrzeba i wykorzystanie lokalnych danych wątków jest niejasna.
  • Widoki są zaśmiecone kodem wyboru bazy danych. Można to wyabstrahować za pomocą widoków opartych na klasach, aby automatycznie wybrać bazę danych na podstawie parametrów żądania w taki sam sposób, w jaki oprogramowanie pośredniczące wybiera domyślną bazę danych.
  • Menedżer kontekstu, aby wybrać bazę danych, musi być owinięty wokół zestawu zapytań w taki sposób, aby menedżer kontekstu był nadal aktywny, gdy zapytanie jest oceniane.

Sugestie

Jeśli potrzebujesz elastycznego dostępu do bazy danych, proponuję użyć routerów bazodanowych Django. Użyj oprogramowania pośredniego lub widoku Mixin, który automatycznie konfiguruje domyślną bazę danych do użycia dla połączenia na podstawie parametrów żądania. Być może trzeba będzie skorzystać z wątków danych lokalnych, aby przechowywać domyślną bazę danych, która ma być używana, tak aby po trafieniu router wiedział, do której bazy danych skierować trasę. Pozwala to Django na używanie istniejących trwałych połączeń z bazą danych (która może znajdować się na różnych hostach, jeśli jest taka potrzeba) i wybiera bazę danych do użycia na podstawie routingu ustawionego w żądaniu.

Takie podejście ma również tę zaletę, że bazę danych dla zapytania można w razie potrzeby zastąpić za pomocą QuerySet using() funkcja wyboru bazy danych innej niż domyślna.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. connect ECONNREFUSED - węzeł js , sql

  2. MySQL Błąd 1064 podczas dodawania klucza obcego za pomocą MySQL Workbench

  3. Problem z kodowaniem znaków

  4. Zapytanie MySQL oszalał?

  5. Najlepszy sposób na bezpieczne połączenie z MySQL za pomocą PHP