4 python string.format json mysql-python
我的目标是使用库将 JSON 对象存储到 json 类型的 MySQL 数据库字段中mysql.connector。
import mysql.connector
import json
jsonData = json.dumps(origin_of_jsonData)
cnx = mysql.connector.connect(**config_defined_elsewhere)
cursor = cnx.cursor()
cursor.execute('CREATE DATABASE dataBase')
cnx.database = 'dataBase'
cursor = cnx.cursor()
cursor.execute('CREATE TABLE table (id_field INT NOT NULL, json_data_field JSON NOT NULL, PRIMARY KEY (id_field))')
Run Code Online (Sandbox Code Playgroud)
现在,下面的代码可以正常工作,我的问题的重点是“%s”的使用:
insert_statement = "INSERT INTO table (id_field, json_data_field) VALUES (%s, %s)"
values_to_insert = (1, jsonData)
cursor.execute(insert_statement, values_to_insert)
Run Code Online (Sandbox Code Playgroud)
我的问题是:在将变量 aValue(s) 组合成一个字符串时,我非常严格地坚持使用'...{}'.format(aValue)(or f'...{aValue}'),从而避免使用%s(不管我的原因是什么,我们不要在这里辩论它们 - 但它是如何我想尽可能保留它,因此我的问题)。
在任何情况下,无论我尝试哪种方式,我都无法使用类似于上述结构并使用'...{}'.format()(以任何形状或形式)而不是%s. 例如,我(在多次迭代中)尝试过
insert_statement = "INSERT INTO table (id_field, json_data_field) VALUES ({}, {})".format(1, jsonData)
cursor.execute(insert_statement)
Run Code Online (Sandbox Code Playgroud)
但无论我如何转动和扭曲它,我都会收到以下错误:
ProgrammingError: 1064 (42000): 你的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以获取在第 1 行的 '[some_content_from_jsonData})]' 附近使用的正确语法
现在我的问题:
1) 有没有办法避免在这里使用我遗漏的 %s?
2)如果不是,为什么?是什么让这一切变得不可能?它是cursor.execute()函数,还是它是一个 JSON 对象的事实,还是完全不同的东西?不{}.format()应该做所有%s可以做的事情,甚至更多吗?
首先:永远不要直接将您的数据插入到您的查询字符串中!
使用%s在MySQL查询字符串是不一样的Python字符串使用它。在 python 中,你只需格式化字符串并'hello %s!' % 'world'变成'hello world!'. 在 SQL 中,%s信号参数插入。这将您的查询和数据分别发送到服务器。您也不受此语法的约束。python DB-API 规范为此指定了更多样式:DB-API 参数样式 (PEP 249)。与将数据直接插入查询字符串相比,这有几个优点:
假设您有一个通过密码对用户进行身份验证的查询。您可以使用以下查询来做到这一点(当然,您通常会加盐并散列密码,但这不是本问题的主题):
SELECT 1 FROM users WHERE username='foo' AND password='bar'
Run Code Online (Sandbox Code Playgroud)
构造此查询的天真方法是:
"SELECT 1 FROM users WHERE username='{}' AND password='{}'".format(username, password)
Run Code Online (Sandbox Code Playgroud)
但是,如果有人输入' OR 1=1密码会发生什么。格式化的查询然后将变成
SELECT 1 FROM users WHERE username='foo' AND password='' OR 1=1
Run Code Online (Sandbox Code Playgroud)
这将始终返回 1。使用参数插入时:
execute('SELECT 1 FROM users WHERE username=%s AND password=%s', username, password)
Run Code Online (Sandbox Code Playgroud)
这永远不会发生,因为查询将由服务器单独解释。
如果使用不同的数据多次运行相同的查询,则使用格式化查询和参数插入之间的性能差异可能很大。使用参数插入,服务器只需编译一次查询(因为每次都是相同的)并使用不同的数据执行它,但是对于字符串格式,它必须一遍又一遍地编译它。
小智 5
除了上面所说的,我想补充一些我没有立即理解的细节,其他(像我这样的新手;))也可能会有所帮助:
1)“参数插入”仅适用于值,它不适用于表名、列名等 - 对于这些,Python 字符串替换在 sql 语法定义中工作正常
2)cursor.execute 函数需要一个元组才能工作(如这里指定的,虽然不是立即清楚,至少对我来说:https : //dev.mysql.com/doc/connector-python/en/connector-python-api -mysqlcursor-execute.html )
一个函数中两者的示例:
def checkIfRecordExists(column, table, condition_name, condition_value):
...
sqlSyntax = 'SELECT {} FROM {} WHERE {} = %s'.format(column, table, condition_name)
cursor.execute(sqlSyntax, (condition_value,))
Run Code Online (Sandbox Code Playgroud)
注意初始 sql 语法定义中 .format 的使用和执行函数中 (condition_value,) 的使用。