连接/引擎¶

如何配置日志记录?

配置日志记录 .

如何池数据库连接?我的关系合并了吗?

在大多数情况下,SQLAlchemy自动执行应用程序级连接池。除了sqlite,a Engine 对象引用了 QueuePool 作为连接的来源。

有关详细信息,请参阅 引擎配置连接池 .

如何将自定义连接参数传递到数据库API?

这个 create_engine() 调用接受其他参数,或者直接通过 connect_args 关键字参数:

e = create_engine("mysql://scott:tiger@localhost/test",
                    connect_args={"encoding": "utf8"})

或者对于基本的字符串和整数参数,通常可以在URL的查询字符串中指定它们:

e = create_engine("mysql://scott:tiger@localhost/test?encoding=utf8")

“MySQL服务器已经消失”

此错误的主要原因是MySQL连接已超时,并且已被服务器关闭。mysql服务器关闭空闲一段时间的连接,默认为8小时。为了适应这种情况,立即设置为启用 create_engine.pool_recycle 设置,这将确保早于设置的秒数的连接将被丢弃,并在下次签出时替换为新连接。

对于适应数据库重新启动和其他由于网络问题导致的临时连接丢失的更一般的情况,池中的连接可以根据更普遍的断开检测技术进行回收。断面 处理断开连接 提供“悲观”(如预ping)和“乐观”(如优雅恢复)技术的背景。现代的SQLAlchemy倾向于“悲观”的方法。

“命令不同步;现在不能运行此命令”/“此结果对象不返回行。它已自动关闭”

MySQL驱动程序有相当广泛的故障模式,其中到服务器的连接状态处于无效状态。通常,当再次使用连接时,会出现这两条错误消息之一。原因是服务器的状态已更改为客户机库不期望的状态,这样当客户机库在连接上发出新语句时,服务器不会按预期响应。

在sqlAlchemy中,由于数据库连接被合并,连接上的消息传递不同步的问题变得更加重要,因为当一个操作失败时,如果连接本身处于不可用状态,如果它返回到连接池,当再次签出时,它将出现故障。这个问题的缓解措施是 失效的 当出现这样的故障模式时,将放弃与MySQL的底层数据库连接。对于许多已知的故障模式,这种失效会自动发生,也可以通过 Connection.invalidate() 方法。

在这个类别中还有第二类失败模式,其中上下文管理器如 with session.begin_nested(): 希望在发生错误时“回滚”事务;但是在连接的某些失败模式中,回滚本身(也可以是释放保存点操作)也会失败,从而导致堆栈跟踪误导。

最初,这个错误的原因相当简单,它意味着多线程程序正在从多个线程对单个连接调用命令。这适用于原始的“mysqldb”本机C驱动程序,它几乎是唯一使用的驱动程序。但是,随着pymysql和mysql connector python等纯python驱动程序的引入,以及gevent/eventlet、多处理(通常使用celery)等工具的使用量的增加,导致这个问题的因素有一系列,其中一些已经在sqlachemy版本中得到了改进,但是其他的一些已经在sqlachemy版本中得到了改进。不可避免的风险:

为什么SQLAlchemy会发布这么多回滚?

SQLAlchemy当前假定DBAPI连接处于“非自动提交”模式-这是Python数据库API的默认行为,这意味着必须假定事务始终在进行中。连接池问题 connection.rollback() 当返回连接时。这是为了释放连接上剩余的任何事务性资源。在像postgresql或mssql这样的数据库中,表资源被严重锁定,这是非常重要的,这样行和表就不会在不再使用的连接中保持锁定。否则,应用程序可能挂起。但是,它不仅适用于锁,而且对于任何具有任何事务隔离的数据库(包括使用innodb的mysql)同样重要。如果在隔离的连接中已经查询了旧事务中的数据,那么仍然在旧事务中的任何连接都将返回过时的数据。有关即使在MySQL上也可能看到过时数据的背景,请参阅http://dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html

我在Myisam上-我怎么关掉它?

连接池的连接返回行为可以使用配置 reset_on_return ::

from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool

engine = create_engine('mysql://scott:tiger@localhost/myisam_database', pool=QueuePool(reset_on_return=False))

我在SQL Server上-如何将这些回滚转换为提交?

reset_on_return 接受值 commitrollback 除了 TrueFalseNone . 设置为 commit 将导致提交,因为任何连接都将返回池::

engine = create_engine('mssql://scott:tiger@mydsn', pool=QueuePool(reset_on_return='commit'))

我正在使用与一个sqlite数据库的多个连接(通常用于测试事务操作),而我的测试程序不工作!

如果使用sqlite :memory: 数据库或0.7版之前的SQLAlchemy版本,默认连接池是 SingletonThreadPool ,每个线程只维护一个SQLite连接。所以在同一线程中使用的两个连接实际上是同一个sqlite连接。确保您没有使用 :memory: database and use NullPool 这是当前SQLAlchemy版本中非内存数据库的默认值。

参见

线程/池行为 -关于pysqlite行为的信息。

使用引擎时,如何获得原始DBAPI连接?

通过常规的SA引擎级连接,您可以通过 Connection.connection 属性对 Connection 对于真正的DBAPI连接,可以调用 ConnectionFairy.connection 属性-但不需要访问非池代理DBAPI连接,因为所有方法都是通过以下方式代理的:

engine = create_engine(...)
conn = engine.connect()
conn.connection.<do DBAPI things>
cursor = conn.connection.cursor(<DBAPI specific arguments..>)

在将连接恢复到池之前,必须确保将连接上的任何隔离级别设置或其他操作特定设置恢复为正常设置。

作为恢复设置的替代方法,您可以调用 Connection.detach() 方法 Connection 或代理连接,它将取消与池中的连接的关联,以便在 Connection.close() 被称为:

conn = engine.connect()
conn.detach()  # detaches the DBAPI connection from the connection pool
conn.connection.<go nuts>
conn.close()  # connection is closed for real, the pool replaces it with a new connection

如何将引擎/连接/会话与python multiprocessing或os.fork()一起使用?

多个Python进程的关键目标是防止任何数据库连接在进程间共享。根据驱动程序和操作系统的具体情况,这里出现的问题从非工作连接到多个进程同时使用的套接字连接,从而导致消息传递中断(后者通常是最常见的情况)。

圣卢西亚 Engine 对象引用现有数据库连接的连接池。因此,当将此对象复制到子进程时,目标是确保不传递任何数据库连接。对此,有三种一般方法:

  1. 禁用池使用 NullPool . 这是最简单的一次系统,可以防止 Engine 多次使用任何连接。

  2. 调用 Engine.dispose() 在任何给定的 Engine 一旦进入新的过程。在Python多处理中,构造 multiprocessing.Pool 包括“初始值设定项”挂钩,该挂钩是可以执行此操作的位置;否则在其中的顶部 os.fork() 或者在哪里 Process 对象开始子分叉,对 Engine.dispose() 将确保刷新所有剩余的连接。

  3. 事件处理程序可以应用于连接池,该池测试跨进程边界共享的连接,并使它们失效。如下所示:

    import os
    import warnings
    
    from sqlalchemy import event
    from sqlalchemy import exc
    
    def add_engine_pidguard(engine):
        """Add multiprocessing guards.
    
        Forces a connection to be reconnected if it is detected
        as having been shared to a sub-process.
    
        """
    
        @event.listens_for(engine, "connect")
        def connect(dbapi_connection, connection_record):
            connection_record.info['pid'] = os.getpid()
    
        @event.listens_for(engine, "checkout")
        def checkout(dbapi_connection, connection_record, connection_proxy):
            pid = os.getpid()
            if connection_record.info['pid'] != pid:
                # substitute log.debug() or similar here as desired
                warnings.warn(
                    "Parent process %(orig)s forked (%(newproc)s) with an open "
                    "database connection, "
                    "which is being discarded and recreated." %
                    {"newproc": pid, "orig": connection_record.info['pid']})
                connection_record.connection = connection_proxy.connection = None
                raise exc.DisconnectionError(
                    "Connection record belongs to pid %s, "
                    "attempting to check out in pid %s" %
                    (connection_record.info['pid'], pid)
                )

    这些事件应用于 Engine 一经创建:

    engine = create_engine("...")
    
    add_engine_pidguard(engine)

上述策略将适应 Engine 在进程之间共享。但是,对于活动事务的情况 SessionConnection 由于是共享的,因此没有自动修复;应用程序需要确保新的子进程只启动新的 Connection 对象和事务以及ORM Session 对象。对于一个 Session 对象,从技术上讲,仅当会话当前是事务绑定的,而单个 Session 在任何情况下都要保持在单个调用堆栈中(例如,不是全局对象,不在进程或线程之间共享)。