SQLAlchemy:引擎,连接和会话差异

olo*_*bus 103 python orm session sqlalchemy psycopg2

我使用SQLAlchemy并至少有三个实体:engine,session并且connection,其中有execute方法,所以如果我如想选择所有记录,从table我能做到这一点

engine.execute(select([table])).fetchall()
Run Code Online (Sandbox Code Playgroud)

还有这个

connection.execute(select([table])).fetchall()
Run Code Online (Sandbox Code Playgroud)

甚至这个

session.execute(select([table])).fetchall()
Run Code Online (Sandbox Code Playgroud)

- 结果将是相同的.

据我所知,如果有人使用engine.execute它创建connection,打开session(Alchemy为你处理它)并执行查询.但这三种执行此类任务的方式之间是否存在全球差异?

Nab*_*med 99

一行概述:

的行为execute()是在所有情况下相同,但它们是3种不同的方法,在Engine,ConnectionSession类.

究竟是什么execute():

要理解execute()我们需要调查Executable课程的行为.Executable是所有"语句"类型对象的超类,包括select(),delete(),update(),insert(),text() - 在最简单的可能的话语中,a Executable是SQLAlchemy中支持的SQL表达式构造.

在所有情况下,该execute()方法都采用SQL文本或构造的SQL表达式,即SQLAlchemy中支持的各种SQL表达式结构,并返回查询结果(a ResultProxy- 包装DB-API游标对象以便更方便地访问行列.)


进一步澄清(仅用于概念澄清,而不是推荐的方法):

除了Engine.execute()(无连接执行),Connection.execute()和之外Session.execute(),还可以execute()直接在任何Executable构造上使用.该Executable班有它自己的执行execute()-按照官方文件,一行说明什么的execute()确实是" 编译并执行这个Executable ".在这种情况下,我们需要显式绑定Executable(SQL表达式构造)与Connection对象或Engine对象(隐式获取Connection对象),因此execute()将知道在哪里执行SQL.

以下示例演示得很好 - 给出如下表:

from sqlalchemy import MetaData, Table, Column, Integer

meta = MetaData()
users_table = Table('users', meta,
    Column('id', Integer, primary_key=True),
    Column('name', String(50)))
Run Code Online (Sandbox Code Playgroud)

显式执行Connection.execute()- 将SQL文本或构造的SQL表达式传递给以下execute()方法Connection:

engine = create_engine('sqlite:///file.db')
connection = engine.connect()
result = connection.execute(users_table.select())
for row in result:
    # ....
connection.close()
Run Code Online (Sandbox Code Playgroud)

显式无连接执行,Engine.execute()- 将SQL文本或构造的SQL表达式直接传递给execute()Engine 的方法:

engine = create_engine('sqlite:///file.db')
result = engine.execute(users_table.select())
for row in result:
    # ....
result.close()
Run Code Online (Sandbox Code Playgroud)

隐式执行Executable.execute()- 也是无连接的,并且调用execute()方法Executable,即它execute()直接在SQL表达式构造(一个实例Executable)本身上调用方法.

engine = create_engine('sqlite:///file.db')
meta.bind = engine
result = users_table.select().execute()
for row in result:
    # ....
result.close()
Run Code Online (Sandbox Code Playgroud)

注意:说明隐式执行示例是为了澄清 - 强烈建议不要使用这种执行方式 - 根据文档:

"隐式执行"是一种非常古老的使用模式,在大多数情况下比使用模式更令人困惑,并且不鼓励使用它.这两种模式似乎都鼓励在应用程序设计中过度使用权宜之计的"捷径",这会导致以后出现问题.


你的问题:

据我所知,如果有人使用engine.execute,它会创建连接,打开会话(Alchemy会为你关心它)并执行查询.

你是正确的"如果有人使用engine.execute它创建connection"而不是"打开session(Alchemy为你关心它)并执行查询" - 使用Engine.execute()Connection.execute()(几乎)一个相同的东西,在形式上,Connection对象被隐式创建,在后面的例子中,我们明确地实例化它.在这种情况下真正发生的是:

`Engine` object (instantiated via `create_engine()`) -> `Connection` object (instantiated via `engine_instance.connect()`) -> `connection.execute({*SQL expression*})`
Run Code Online (Sandbox Code Playgroud)

但这三种执行此类任务的方式之间是否存在全球差异?

在DB层,它完全相同,所有这些都在执行SQL(文本表达式或各种SQL表达式构造).从应用程序的角度来看,有两种选择:

  • 直接执行 - 使用Engine.execute()Connection.execute()
  • 使用sessions-通过有效地处理交易单单元的工作,轻松session.add(),session.rollback(),session.commit(),session.close().在ORM即映射表的情况下,它是与DB交互的方式.提供identity_map,以便在单个请求期间立即获取已访问或新创建/添加的对象.

Session.execute()最终使用Connection.execute()语句执行方法来执行SQL语句.使用Sessionobject是SQLAlchemy ORM推荐的应用程序与数据库交互的方式.

文档的摘录:

重要的是要注意,在使用SQLAlchemy ORM时,通常不会访问这些对象; 相反,Session对象用作数据库的接口.但是,对于围绕直接使用文本SQL语句和/或SQL表达式构造的应用程序而没有ORM的更高级别管理服务的参与,引擎和连接是王者(和女王?) - 继续阅读.


Nea*_*eal 83

Nabeel的回答涵盖了很多细节,并且很有帮助,但我发现它很容易引起注意.由于这是目前此问题的第一个Google结果,因此在未来发现此问题的人员中添加我对它的理解:

运行.execute()

正如OP和Nabell Ahmed都注意到的那样,在执行平原时SELECT * FROM tablename,所提供的结果没有区别.

这三个对象之间的差异确实很重要,具体取决于SELECT使用该语句的上下文,或者更常见的是,当您想要执行其他操作INSERTDELETE,等等.

何时一般使用Engine,Connection,Session

  • Engine是SQLAlchemy使用的最低级别对象.只要应用程序需要与数据库通信,它就会维护一个可用的连接池..execute()是一个方便的方法,该方法首先调用conn = engine.connect(close_with_result=True)和然后conn.execute().close_with_result参数表示连接自动关闭.(我稍微解释了源代码,但基本上是正确的).

    您可以使用引擎来执行原始SQL.

    result = engine.execute('SELECT * FROM tablename;')
    #what engine.execute() is doing under the hood
    conn = engine.connect(close_with_result=True)
    result = conn.execute('SELECT * FROM tablename;')
    
    #after you iterate over the results, the result and connection get closed
    for row in result:
        print(result['columnname']
    
    #or you can explicitly close the result, which also closes the connection
    result.close()
    
    Run Code Online (Sandbox Code Playgroud)

    这在基本用法下的文档中有所介绍.

  • 连接(如上所述)实际执行SQL查询的工作.每当您想要更好地控制连接的属性,关闭连接等时,都应该这样做.例如,一个非常重要的示例是一个Transaction,它允许您决定何时提交对数据库的更改.在正常使用中,更改是自动提交的.通过使用事务,您可以(例如)运行多个不同的SQL语句,如果其中一个出现问题,您可以立即撤消所有更改.

    connection = engine.connect()
    trans = connection.begin()
    try:
        connection.execute("INSERT INTO films VALUES ('Comedy', '82 minutes');")
        connection.execute("INSERT INTO datalog VALUES ('added a comedy');")
        trans.commit()
    except:
        trans.rollback()
        raise
    
    Run Code Online (Sandbox Code Playgroud)

    如果一个失败,这将允许您撤消这两个更改,就像忘记创建数据记录表一样.

    因此,如果您正在执行原始SQL代码并需要控制,请使用连接

  • 会话用于SQLAlchemy的对象关系管理(ORM)方面(事实上,您可以从导入它们的方式看到这一点:) from sqlalchemy.orm import sessionmaker.他们使用引擎下的连接和事务来运行自动生成的SQL语句..execute()是一个便利函数,它传递给会话所绑定的任何内容(通常是引擎,但可以是连接).

    如果您正在使用ORM功能,请使用会话; 如果你只做直接的SQL查询没有绑定到对象,你可能最好直接使用连接.

  • @mingchau是的,您是对的,我的单引号会互相干扰,双引号更容易避免该问题。更新。 (2认同)
  • 我正在使用会话,查询完成后我也会关闭它。我有时仍然会发现数据库被锁定。任何想法? (2认同)