sql >> データベース >  >> RDS >> Mysql

マルチテナントDjangoアプリケーション:リクエストごとにデータベース接続を変更しますか?

    ポイント1に最も近い同様のことを行いましたが、ミドルウェアを使用してデフォルトの接続を設定する代わりに、Djangoデータベースルーターが使用されます。これにより、アプリケーションロジックは、リクエストごとに必要に応じて、多数のデータベースを使用できます。すべてのクエリに適したデータベースを選択するのはアプリケーションロジック次第であり、これがこのアプローチの大きな欠点です。

    この設定では、すべてのデータベースがsettings.DATABASESに一覧表示されます。 、顧客間で共有される可能性のあるデータベースを含みます。顧客固有の各モデルは、特定のアプリラベルを持つDjangoアプリに配置されます。

    例えば。次のクラスは、すべての顧客データベースに存在するモデルを定義します。

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

    データベースルーターはsettings.DATABASE_ROUTERSに配置されます app_labelによってデータベースリクエストをルーティングするチェーン 、このようなもの(完全な例ではありません):

    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)
    

    このルーターの特別な部分は、thread_local_data.current_customer_db()です。 電話。ルーターを実行する前に、呼び出し元/アプリケーションは、現在の顧客データベースをthread_local_dataに設定しておく必要があります。 。この目的でPythonコンテキストマネージャーを使用して、現在の顧客データベースをプッシュ/ポップできます。

    これらすべてを構成すると、アプリケーションコードは次のようになります。UseCustomerDatabase 現在の顧客データベース名をthread_local_dataにプッシュ/ポップするコンテキストマネージャーです。 そのため、thread_local_data.current_customer_db() ルーターが最終的にヒットしたときに正しいデータベース名を返します:

    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)
    

    これはすでにかなり複雑な設定です。それは機能しますが、私が見ている長所と短所を要約してみます:

    利点

    • データベースの選択は柔軟です。 1つのクエリで複数のデータベースを使用でき、リクエストでは顧客固有のデータベースと共有データベースの両方を使用できます。
    • データベースの選択は明示的です(これが長所か短所かはわかりません)。顧客データベースにヒットするクエリを実行しようとしたが、アプリケーションがクエリを選択しなかった場合、プログラミングエラーを示す例外が発生します。
    • データベースルーターを使用すると、USE db;に依存するのではなく、さまざまなデータベースをさまざまなホストに存在させることができます。 すべてのデータベースが単一の接続を介してアクセス可能であると推測するステートメント。

    短所

    • セットアップは複雑で、機能させるにはかなりの数のレイヤーが必要です。
    • スレッドローカルデータの必要性と使用法はあいまいです。
    • ビューにはデータベース選択コードが散らばっています。これは、ミドルウェアがデフォルトのデータベースを選択するのと同じ方法で、リクエストパラメータに基づいてデータベースを自動的に選択するために、クラスベースのビューを使用して抽象化できます。
    • データベースを選択するコンテキストマネージャーは、クエリの評価時にコンテキストマネージャーが引き続きアクティブになるように、クエリセットをラップする必要があります。

    提案

    柔軟なデータベースアクセスが必要な場合は、Djangoのデータベースルーターを使用することをお勧めします。ミドルウェアまたはビューMixinを使用して、要求パラメーターに基づいて接続に使用するデフォルトのデータベースを自動的にセットアップします。使用するデフォルトのデータベースを格納するためにスレッドローカルデータに頼らなければならない場合があります。これにより、ルーターがヒットしたときに、どのデータベースにルーティングするかがわかります。これにより、Djangoはデータベース(必要に応じて別のホストに存在する場合があります)への既存の永続的な接続を使用でき、リクエストで設定されたルーティングに基づいて使用するデータベースを選択します。

    このアプローチには、 QuerySet using() デフォルト以外のデータベースを選択する機能。



    1. SQLServerでのSETROWCOUNTの動作

    2. いつカーソルとデータベースを閉じる必要がありますか?

    3. タイムスタンプに日を追加

    4. 不動産の専​​門家がMicrosoftAccessを使用する方法