<p>SQL炼金术会话对象有自己的<code>execute</code>方法:</p>
<pre><code>result = db.session.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})
</code></pre>
<p><strong>所有应用程序查询都应通过会话对象,无论它们是否是原始SQL。这可以确保查询正确地<a href="https://docs.sqlalchemy.org/en/latest/orm/session_transaction.html" rel="noreferrer">managed by a transaction</a>,从而允许同一请求中的多个查询作为单个单元提交或回滚。使用<a href="https://stackoverflow.com/a/17987782/1394393">engine</a>或<a href="https://stackoverflow.com/a/18808942/1394393">connection</a>离开事务会使您面临更大的风险,即可能很难检测到可能会导致数据损坏的错误。每个请求应该只与一个事务相关联,使用<code>db.session</code>将确保您的应用程序是这样的。</p>
<p>还要注意<code>execute</code>是为<a href="https://stackoverflow.com/a/4712113/1394393">parameterized queries</a>设计的。对查询的任何输入使用参数,如示例中的<code>:val</code>,以保护自己免受SQL注入攻击。您可以通过将<code>dict</code>作为第二个参数传递来提供这些参数的值,其中每个键都是参数在查询中显示的名称。参数本身的确切语法可能因数据库而异,但所有主要关系数据库都以某种形式支持它们。</p>
<p>假设它是一个<code>SELECT</code>查询,这将返回<a href="https://docs.sqlalchemy.org/en/latest/core/connections.html?highlight=resultproxy#sqlalchemy.engine.ResultProxy" rel="noreferrer">an iterable</a>个<a href="https://docs.sqlalchemy.org/en/latest/core/connections.html?highlight=rowproxy#sqlalchemy.engine.RowProxy" rel="noreferrer">^{<cd7>}</a>对象。</p>
<p>可以使用多种技术访问各个列:</p>
<pre><code>for r in result:
print(r[0]) # Access by positional index
print(r['my_column']) # Access by column name as a string
r_dict = dict(r.items()) # convert to dict keyed by column names
</code></pre>
<p>就我个人而言,我更喜欢将结果转换成<code>namedtuple</code>s:</p>
<pre><code>from collections import namedtuple
Record = namedtuple('Record', result.keys())
records = [Record(*r) for r in result.fetchall()]
for r in records:
print(r.my_column)
print(r)
</code></pre>
<hr/>
<p>如果不使用Flask SQLAlchemy扩展,则仍然可以轻松使用会话:</p>
<pre><code>import sqlalchemy
from sqlalchemy.orm import sessionmaker, scoped_session
engine = sqlalchemy.create_engine('my connection string')
Session = scoped_session(sessionmaker(bind=engine))
s = Session()
result = s.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})
</code></pre>