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

2024-05-19 01:36:05 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

还有这个

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

甚至这个

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

-结果是一样的。

据我所知,如果有人使用engine.execute,它会创建connection,打开session(炼金术为您处理)并执行查询。但这三种方式在全球范围内是否有差异 任务?


Tags: 方法实体executesqlalchemysession方式记录table
3条回答

单行概述:

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

究竟是什么execute()

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

在所有情况下,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表达式直接传递给引擎的execute()方法:

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

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

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

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

“implicit execution” is a very old usage pattern that in most cases is more confusing than it is helpful, and its usage is discouraged. Both patterns seem to encourage the overuse of expedient “short cuts” in application design which lead to problems later on.


你的问题:

As I understand if someone use engine.execute it creates connection, opens session (Alchemy cares about it for you) and executes query.

对于“如果有人使用engine.execute,它会创建connection”,而不是“打开session(炼金术会关心你)并执行查询”这一部分,你是对的——使用Engine.execute()Connection.execute()是(几乎)同一件事,在形式上,Connection对象是隐式创建的,在以后的情况下,我们显式实例化它。在这种情况下真正发生的是:

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

But is there a global difference between these three ways of performing such task?

在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

Its important to note that when using the SQLAlchemy ORM, these objects are not generally accessed; instead, the Session object is used as the interface to the database. However, for applications that are built around direct usage of textual SQL statements and/or SQL expression constructs without involvement by the ORM’s higher level management services, the Engine and Connection are king (and queen?) - read on.

下面是一个运行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

Nabeel's answer涵盖了很多细节,并且很有帮助,但是我发现下面的内容很混乱。因为这是目前谷歌针对这一问题的第一个搜索结果,所以我对这一问题的进一步理解将为以后发现这一问题的人提供:

运行。执行()

正如OP和Nabell Ahmed都注意到的那样,当执行一个普通的SELECT * FROM tablename时,所提供的结果没有区别。

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

一般情况下何时使用引擎、连接、会话

  • 引擎是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下的文档中有介绍。

  • 连接是(如上所述)实际执行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查询,则最好直接使用连接。

相关问题 更多 >

    热门问题