flask + SQLAlchemy設置讀寫分離

參考文檔

https://www.jb51.net/article/174365.htm
https://gist.github.com/trustrachel/6828122#file-routing-py

步驟

在配置中添加以下配置

SQLALCHEMY_DATABASE_URI = 'xxx'
SQLALCHEMY_BINDS = {
        'xxx',
        'xxx',
    }

改寫session

from flask_sqlalchemy import SQLAlchemy, get_state
import sqlalchemy.orm as orm
from functools import partial

import logging

log = logging.getLogger(__name__)


class AutoRouteSession(orm.Session):

    def __init__(self, db, autocommit=False, autoflush=False, **options):
        self.app = db.get_app()
        self._model_changes = {}
        orm.Session.__init__(self, autocommit=autocommit, autoflush=autoflush,
                             bind=db.engine,
                             binds=db.get_binds(self.app), **options)

    def get_bind(self, mapper=None, clause=None):
        """
        根據配置及讀寫操作,自動更改數據庫引擎
        Args:
            mapper:
            clause:

        Returns:

        """
        try:
            state = get_state(self.app)
        except (AssertionError, AttributeError, TypeError) as err:
            log.info("獲取配置失敗,使用默認數據庫:{}".format(err))
            return orm.Session.get_bind(self, mapper, clause)

        # 如果沒有設置SQLALCHEMY_BINDS,則默認使用SQLALCHEMY_DATABASE_URI
        if state is None or not self.app.config['SQLALCHEMY_BINDS']:
            if not self.app.debug:
                log.debug("未獲取數據庫綁定信息(SQLALCHEMY_BINDS),使用默認數據庫")
            return orm.Session.get_bind(self, mapper, clause)

        # insert、update、delete操作使用master
        elif self._flushing:
            log.debug("當前使用master")
            return state.db.get_engine(self.app, bind='master')

        # 其他操作使用slave
        else:
            log.debug("當前使用slave")
            return state.db.get_engine(self.app, bind='slave')


class AutoRouteSQLAlchemy(SQLAlchemy):

    def create_scoped_session(self, options=None):
        """
        用於工廠類創建session
        Args:
            options:

        Returns:

        """
        if options is None:
            options = {}
        scopefunc = options.pop('scopefunc', None)
        return orm.scoped_session(
            partial(AutoRouteSession, self, **options), scopefunc=scopefunc
        )

實例化

db = AutoRouteSQLAlchemy()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章