繁体   English   中英

如果仅用于原始SQL查询,SQLAlchemy仍然是推荐的吗?

[英]Is SQLAlchemy still recommended if only used for raw sql query?

使用Flask,我很想知道SQLAlchemy是否仍然是使用原始SQL(直接SELECT x FROM table WHERE ... )查询数据库的最佳方式,而不是使用ORM或者是否有更简单但功能更强大的替代方案?

谢谢你的回复。

我一直使用SQLAlchemy进行直接查询。

主要优点:它为您提供针对SQL注入攻击的最佳保护。 SQLAlchemy做了正确的事情,无论你抛出什么参数。

我发现它也可以根据条件调整生成的SQL。 显示上面有多个过滤器控件的结果集? 只需在一组if / elif / else结构中构建查询,您就知道您的SQL仍然是金色的。

以下是一些实时代码的摘录(较旧的SA版本,因此语法可能略有不同):

# Pull start and end dates from form
# ...
# Build a constraint if `start` and / or `end` have been set.
created = None
if start and end:
    created = sa.sql.between(msg.c.create_time_stamp, 
        start.replace(hour=0, minute=0, second=0),
        end.replace(hour=23, minute=59, second=59))
elif start:
    created = (msg.c.create_time_stamp >= 
               start.replace(hour=0, minute=0, second=0))
elif end:
    created = (msg.c.create_time_stamp <= 
               end.replace(hour=23, minute=59, second=59))

# More complex `from_` object built here, elided for example
# [...]
# Final query build
query = sa.select([unit.c.eli_uid], from_obj=[from_])
query = query.column(count(msg.c.id).label('sent'))
query = query.where(current_store)
if created:
    query = query.where(created)

这来自的代码要复杂得多,但我想在这里突出显示日期范围代码。 如果我必须使用字符串格式化构建SQL,我可能已经在某处引入了SQL注入漏洞,因为它更容易忘记引用值。

在我处理了一个小项目之后,我决定尝试使用MySQLDB,而不使用SQL Alchemy。

它工作正常,使用起来非常简单,这是一个例子(我创建了一个小类来处理数据库的所有工作)

import MySQLdb
from MySQLdb.cursors import DictCursor

class DatabaseBridge():
    def __init__(self, *args, **kwargs):
        kwargs['cursorclass'] = DictCursor
        self.cnx = MySQLdb.connect (**kwargs)
        self.cnx.autocommit(True)
        self.cursor = self.cnx.cursor()

    def query_all(self, query, *args):
        self.cursor.execute(query, *args)
        return self.cursor.fetchall()

    def find_unique(self, query, *args):
        rows = self.query_all(query, *args);
        if len(rows) == 1:
            return rows[0]

        return None

    def execute(self, query, params):
        self.cursor.execute(query, params)
        return self.cursor.rowcount

    def get_last_id(self):
        return self.cnx.insert_id()

    def close(self):
        self.cursor.close()
        self.cnx.close()

database = DatabaseBridge(**{
        'user': 'user',
        'passwd': 'password',
        'db': 'my_db'
    })

rows = database.query_all("SELECT id, name, email FROM users WHERE is_active = %s AND project = %s", (1, "My First Project"))

(这是一个愚蠢的例子)。

它就像一个魅力, 你必须考虑到这些:

  • 不支持多线程! 如果你不使用Python的multiprocessing ,那没关系。
  • 您将无法获得SQLAlchemy(数据库到类(模型)包装器,查询生成(select,where,order_by等))的所有优点。 这是您希望如何使用数据库的关键点。

但另一方面,和SQLAlchemy一样,还有针对SQL注入攻击的保护:

一个基本的查询是这样的:

cursor.execute("SELECT * FROM users WHERE data = %s" % "Some value") # THIS IS DANGEROUS

但你应该这样做:

cursor.execute("SELECT * FROM users WHERE data = %s", ("Some value",)) # This is secure!

看到了区别? 再读一遍;)

不同的是,我代替% ,由, :我们通过参数作为...参数的执行,而这些都逃脱了。 使用% ,参数不会被转义,从而启用SQL注入攻击!

这里的最后一句话是,它取决于您的使用情况以及您计划如何处理项目。 对我来说,SQLAlchemy过度使用(这是一个基本的shell脚本!),所以MysqlDB很完美。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM