问题:SQLAlchemy:引擎,连接和会话的区别
我使用SQLAlchemy并至少有三个实体:engine
,session
并且connection
,其中有execute
方法,所以如果我如想选择所有记录table
我能做到这一点
engine.execute(select([table])).fetchall()
还有这个
connection.execute(select([table])).fetchall()
甚至这个
session.execute(select([table])).fetchall()
-结果将是相同的。
据我了解,如果有人使用engine.execute
它connection
,它会创建,打开session
(Alchemy会为您处理)并执行查询。但是,执行此任务的这三种方式之间是否存在全局差异?
回答 0
单行概述:
的行为execute()
是在所有情况下相同,但它们是3种不同的方法,在Engine
,Connection
和Session
类。
到底是什么execute()
:
要了解行为,execute()
我们需要调查Executable
该类。Executable
是所有“语句”类型对象的超类,包括select(),delete(),update(),insert(),text()-用最简单的词来说,Executable
是SQLAlchemy支持的SQL表达式构造。
在所有情况下,该execute()
方法均采用SQL文本或构造的SQL表达式,即SQLAlchemy支持的各种SQL表达式构造,并返回查询结果(ResultProxy
a-包装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)))
显式执行,即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()
显式无连接执行,即Engine.execute()
-将SQL文本或构造的SQL表达式直接传递给execute()
Engine方法:
engine = create_engine('sqlite:///file.db')
result = engine.execute(users_table.select())
for row in result:
# ....
result.close()
隐式执行(即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()
注意:出于说明的目的,陈述了隐式执行示例-强烈建议不按照这种方式执行这种执行方式-按照docs:
“隐式执行”是一个非常古老的使用模式,在大多数情况下,它比有用的方法更令人困惑,并且不鼓励使用它。两种模式似乎都鼓励在应用程序设计中过度使用权宜之计的“捷径”,这会在以后导致问题。
你的问题:
据我了解,如果有人使用engine.execute,它将创建连接,打开会话(Alchemy会为您关心)并执行查询。
您认为“如果有人使用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*})`
但是,执行此任务的这三种方式之间是否存在全局差异?
在数据库层,这完全是同一回事,所有这些都在执行SQL(文本表达式或各种SQL表达式构造)。从应用程序的角度来看,有两个选项:
- 直接执行-使用
Engine.execute()
或Connection.execute()
- 使用
sessions
-通过有效地处理交易单单元的工作,轻松session.add()
,session.rollback()
,session.commit()
,session.close()
。在ORM(即映射表)的情况下,这是与DB进行交互的方式。提供identity_map,以便在单个请求期间立即获取已被访问的对象或新创建/添加的对象。
Session.execute()
最终使用Connection.execute()
语句执行方法来执行SQL语句。使用Session
对象是SQLAlchemy ORM建议的应用程序与数据库交互的方式。
文档摘录:
重要的是要注意,在使用SQLAlchemy ORM时,通常不访问这些对象。而是将Session对象用作数据库的接口。但是,对于围绕直接使用文本SQL语句和/或SQL表达式构造而无需ORM更高级别的管理服务参与的应用程序,“引擎”和“连接”为王(也是王后?),请继续阅读。
回答 1
Nabeel的答案涵盖了很多细节并且很有帮助,但是我发现难以理解。由于这是该问题的第一个Google结果,因此,我对以后发现此问题的人们加深了理解:
运行.execute()
正如OP和Nabell Ahmed都指出的那样,执行平原时SELECT * FROM tablename
,提供的结果没有区别。
这三个对象之间的区别取决于上下文就成为非常重要的SELECT
声明中,或者更常见的是,当你想要做其他事情一样使用INSERT
,DELETE
等等。
何时使用引擎,连接,会话
引擎是SQLAlchemy使用的最低级别的对象。它维护了一个连接池,可在应用程序需要与数据库对话时使用。
.execute()
是一种先调用conn = engine.connect(close_with_result=True)
然后调用的便捷方法conn.execute()
。close_with_result参数表示连接自动关闭。(我稍微解释了源代码,但本质上是正确的)。编辑:这是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()
在基本用法下的文档中对此进行了介绍。
连接(正如我们在上面看到的)实际上是执行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功能,请使用会话。如果只执行不绑定对象的直接SQL查询,则最好直接使用连接。
回答 2
这是运行诸如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