0

我正在使用 sqlalchemy 的主/从,通过 RoutingSession 之类的

engines = {
    'master':create_engine("sqlite:///master.db"),
    'other':create_engine("sqlite:///other.db"),
    'slave1':create_engine("sqlite:///slave1.db"),
    'slave2':create_engine("sqlite:///slave2.db"),
}

from sqlalchemy.orm import Session, sessionmaker
import random

class RoutingSession(Session):
    def get_bind(self, mapper=None, clause=None):
        if mapper and issubclass(mapper.class_, MyOtherClass):
            return engines['other']
        elif self._flushing:
            return engines['master']
        else:
            return engines[
                random.choice(['slave1','slave2'])
            ]

http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#custom-vertical-partitioning

我在“get_bind”方法中打印了日志。我发现在使用“session.add(r); session.commit()”时,“get_bind”方法被执行了两次。那为什么要两次?

当使用“session.execute('insert ...'); session.commit()”时,“get_bind”方法只被调用一次。

4

1 回答 1

1

会话支持同时关联多个引擎,这些引擎基于映射器或表与会话关联。因此,任何时候 Session 需要与数据库对话,并且它手头有一个特定mapper()的处理,它必须调用get_bind()以便为这个特定的映射器获取正确的引擎。在刷新中,假设存在脏状态(session.add(r) 的结果),一个特定mapper()的被多次查询以准备发出 SQL - 目前至少一次用于“保存”传递,一次用于“删除”通过虽然我可以尝试改进在这种情况下删除不必要的抓取(编辑:完成)。

你总是可以通过坚持import pdb; pdb.set_trace()在它里面,然后每次你到达那里时在控制台上做一个“哪里”来告诉它为什么被调用。

所以通常你应该假设 get_bind() 一直被调用。它被调用的频率并不重要。

编辑:0.8 和 0.7 的最新提示不会调用 get_bind() 当没有要刷新的状态以进行保存/删除传递时,因此现在在此特定测试中调用一次。

于 2012-06-13T14:00:24.147 回答