1

我有类似于以下的代码:

var1 = 1
var2 = 2
cursor.execute("INSERT INTO mytable VALUES (:var1, :var2)", {'var1': var1, 'var2': var2})

有什么理由我应该使用字典文字来传递参数,而不是简单地这样做:

var1 = 1
var2 = 2
cursor.execute("INSERT INTO mytable VALUES (:var1, :var2)", locals())

这感觉更简单,更易于维护,但我无法摆脱这里有某种安全气味的感觉。

4

2 回答 2

3

这不是安全问题(除非您不清理查询字符串本身)。

这是一个维护问题:

  1. 您正在传递“所有内容”,因此编写不佳的查询(即您的拼写错误)可能会从 locals() 中获取意外值。通过更明确,您更有可能抓住这一点。
  2. 您并没有准确地告诉“未来的程序员”您正在使用什么进行查询,因此有人可能会在您的 SQL 调用之前更改参数的值,从而导致意外行为。

在简短的查询(例如您的示例)中,使用locals()并不是这样的悲剧。使用更复杂的查询,例如(我从最近的 emacs 缓冲区中抓取的东西):

WITH RECURSIVE
include_parents(a_id, parent_id, uid, distance) AS ( 
  SELECT accounts.a_id, 
         CASE WHEN admin_can_add THEN NULL
         ELSE accounts.parent_id END AS parent_id, 
         uid, 0 AS distance 
    FROM accounts LEFT OUTER JOIN account_users
         ON (accounts.a_id = account_users.a_id AND admin_can_add)
   WHERE accounts.a_id = $a_id
  UNION ALL 
   SELECT accounts.a_id,
          CASE WHEN admin_can_add THEN NULL
          ELSE accounts.parent_id END as parent_id, 
          account_users.uid, distance + 1 as distance 
     FROM accounts LEFT OUTER JOIN account_users 
          ON (accounts.a_id = account_users.a_id AND admin_can_add), 
          include_parents 
    WHERE accounts.a_id = include_parents.parent_id 
 ) 
SELECT a_id, uid, distance from include_parents 
       WHERE uid IS NOT NULL 

在这种情况下,{'a_id': 14}通过不是locals(). 另外,如果我的查询因寻找我忘记传递的另一个参数而爆炸(可能是因为我从另一个用法稍微改变了这个查询),它将迫使我更仔细地查看我的代码。如果我通过locals()了,查询可能会以我不希望的方式“成功”。

于 2017-05-23T21:08:59.623 回答
-3

如果您使用的是 Python 3.6,则可以使用f-string interpolation

var1 = 1
var2 = 2
cursor.execute(f"INSERT INTO mytable VALUES (:{var1}, :{var2})")
于 2017-05-23T21:44:57.333 回答