【问题标题】:SQLAlchemy: engine, connection and session differenceSQLAlchemy:引擎、连接和会话的区别
【发布时间】:2016-03-23 04:56:50
【问题描述】:

我使用 SQLAlchemy 并且至少有三个实体:enginesessionconnection,它们具有 execute 方法,所以如果我例如想从table中选择所有记录我可以这样做

engine.execute(select([table])).fetchall()

还有这个

connection.execute(select([table])).fetchall()

甚至这个

session.execute(select([table])).fetchall()

- 结果是一样的。

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

【问题讨论】:

标签: python session orm sqlalchemy psycopg2


【解决方案1】:

单行概览:

execute() 的行为在所有情况下都是相同的,但它们是 3 种不同的方法,分别在 EngineConnectionSession 类中。

execute()到底是​​什么:

要了解execute() 的行为,我们需要查看Executable 类。 Executable 是所有“语句”类型对象的超类,包括 select()、delete()、update()、insert()、text() - 用最简单的话来说,Executable 是一个 SQL 表达式结构SQLAlchemy 支持。

在所有情况下,execute() 方法采用 SQL 文本或构造的 SQL 表达式,即 SQLAlchemy 支持的各种 SQL 表达式构造并返回查询结果(ResultProxy - 将 DB-API 游标对象包装到提供对行列的更轻松访问。)


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

除了Engine.execute()(无连接执行)、Connection.execute()Session.execute(),还可以在任何Executable 构造上直接使用execute()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)))

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

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

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

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

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

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

注意:出于澄清目的陈述了隐式执行示例 - 强烈不推荐这种执行方式 - 根据docs

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


您的问题:

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

对于“如果有人使用engine.execute,它会创建connection”这部分是正确的,但对于“打开session(Alchemy 会为您关心它)并执行查询”这部分是正确的——使用Engine.execute() 和@ 987654370@ (几乎)是一回事,在形式上,Connection 对象是隐式创建的,在后面的情况下我们显式地实例化它。在这种情况下真正发生的是:

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

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

在 DB 层完全一样,都是在执行 SQL(文本表达式或各种 SQL 表达式结构)。从应用程序的角度来看,有两种选择:

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

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

摘自docs

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

【讨论】:

  • “connectionless”这个词意味着没有创建连接,根据尼尔的回答并非如此。
【解决方案2】:

Nabeel's answer 涵盖了很多细节并且很有帮助,但我发现它难以理解。由于这是目前针对此问题的第一个 Google 结果,因此为以后发现此问题的人补充我对它的理解:

运行 .execute()

正如 OP 和 Nabell Ahmed 都指出的那样,在执行普通的 SELECT * FROM tablename 时,提供的结果没有区别。

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

Engine、Connection、Session一般什么时候使用

  • Engine 是 SQLAlchemy 使用的最低级别的对象。它maintains a pool of connections 可在应用程序需要与数据库通信时使用。 .execute() 是一种方便的方法,它首先调用conn = engine.connect(close_with_result=True),然后调用conn.execute()。 close_with_result 参数表示连接自动关闭。 (我稍微解释了源代码,但基本上是真的)。 编辑:Here's the source code for engine.execute

    您可以使用引擎执行原始 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()
    

    basic usage 下的文档对此进行了介绍。

  • Connection 是(如我们在上面看到的)实际执行 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
    

    如果其中一项失败,这将让您撤消这两项更改,例如您忘记创建数据记录表。

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

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

    如果您使用 ORM 功能,请使用 session;如果您只执行未绑定到对象的直接 SQL 查询,则最好直接使用连接。

【讨论】:

  • 给定创建的会话,我的会话如何与我的 PostgreSQL 连接链接?
  • @RajuyourPepe my_session.connection()。文档:docs.sqlalchemy.org/en/13/orm/….
  • 认真的吗? 'Session' 对象没有属性 'connect'",这是我发现的
  • @RajuyourPepe 仔细查看命令,它是connection() 而不是connect。请参阅我的文档链接。
  • 我正在使用会话,并且在查询完成时也将其关闭。我有时仍然会发现数据库被锁定。有什么想法吗?
【解决方案3】:

这里是运行 DCL(数据控制语言)如 GRANT 的示例

def grantAccess(db, tb, user):
  import sqlalchemy as SA
  import psycopg2

  url = "{d}+{driver}://{u}:{p}@{h}:{port}/{db}".\
            format(d="redshift",
            driver='psycopg2',
            u=username,
            p=password,
            h=host,
            port=port,
            db=db)
  engine = SA.create_engine(url)
  cnn = engine.connect()
  trans = cnn.begin()
  strSQL = "GRANT SELECT on table " + tb + " to " + user + " ;"
  try:
      cnn.execute(strSQL)
      trans.commit()
  except:
      trans.rollback()
      raise

【讨论】:

  • 你没有检查数据库是否存活?
猜你喜欢
  • 2019-09-30
  • 2016-02-04
  • 1970-01-01
  • 2014-07-08
  • 2016-12-25
  • 2012-09-01
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多