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

时间:2015-12-16 21:29:31

标签: python session orm sqlalchemy psycopg2

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

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

和这个

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

甚至这个

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

- 结果将是相同的。

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

3 个答案:

答案 0 :(得分:82)

一行概述:

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

究竟是什么execute()

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

在所有情况下,execute()方法接受SQL文本或构造的SQL表达式,即SQLAlchemy中支持的各种SQL表达式构造,并返回查询结果(ResultProxy - 包装一个{{ 1}}游标对象,以便更方便地访问行列。)

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

除了DB-API(无连接执行),Engine.execute()Connection.execute()之外,还可以在任何Session.execute()构造上直接使用execute()Executable类具有Executable自己的实现 - 根据官方文档,关于execute()执行的操作的一行描述是" 编译和执行这个execute() "。在这种情况下,我们需要显式绑定Executable(SQL表达式构造)与Executable对象或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))) - 将SQL文本或构造的SQL表达式传递给Connection.execute()的{​​{1}}方法:

execute()

显式无连接执行,即Connection - 将SQL文本或构造的SQL表达式直接传递给Engine的engine = create_engine('sqlite:///file.db') connection = engine.connect() result = connection.execute(users_table.select()) for row in result: # .... connection.close() 方法:

Engine.execute()

隐式执行execute() - 也是无连接的,并调用engine = create_engine('sqlite:///file.db') result = engine.execute(users_table.select()) for row in result: # .... result.close() 的{​​{1}}方法,即调用Executable.execute()方法直接在execute()表达式构造(Executable的一个实例)本身。

execute()

注意:为了澄清,说明了隐式执行示例 - 强烈建议不要使用这种执行方式 - 按docs

  

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

您的问题:

  

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

你是正确的部分"如果某人使用SQL,它会创建Executable"但不是"打开engine = create_engine('sqlite:///file.db') meta.bind = engine result = users_table.select().execute() for row in result: # .... result.close() (Alchemy为你关心它)并执行查询" - 使用engine.executeconnection几乎是一样的,在正式的session对象中隐式创建,在后面的例子中我们显式地实例化它。在这种情况下真正发生的是:

Engine.execute()
  

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

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

  • 直接执行 - 使用Connection.execute()Connection
  • 使用`Engine` object (instantiated via `create_engine()`) -> `Connection` object (instantiated via `engine_instance.connect()`) -> `connection.execute({*SQL expression*})` - 有效地将事务处理为单个事务 通过Engine.execute()Connection.execute()sessionssession.add()轻松完成工作单元。在ORM(即映射表)的情况下,它是与DB交互的方式。提供identity_map以便在单个请求期间立即获取已访问或新创建/添加的对象。

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

摘自docs

  

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

答案 1 :(得分:63)

Nabeel's answer涵盖了很多详细信息并且很有帮助,但我发现它很容易引起注意。由于这是目前此问题的第一个Google搜索结果,因此我将其理解为未来发现此问题的人:

正在运行.execute()

OP和Nabell Ahmed都注意到,在执行普通SELECT * FROM tablename时,所提供的结果没有区别。

根据SELECT语句的使等等。

何时使用引擎,连接,会话

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

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

    conn = engine.connect(close_with_result=True)

    basic usage下的文档中介绍了这一点。

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

    conn.execute()

    这可以让你在失败时撤消这两个更改,比如忘记创建数据记录表。

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

  • 会话用于SQLAlchemy的对象关系管理(ORM)方面(事实上,您可以从导入它们的方式看到这一点: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() )。他们使用引擎下的连接和事务来运行自动生成的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 是一个便捷函数,它传递给会话绑定的任何内容(通常是引擎,但可以是连接)。

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

答案 2 :(得分:0)

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

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