我的目标是使用mysql.connector
库将JSON对象存储到json类型的MySQL数据库字段中。
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))')
现在,下面的代码工作正常,我的问题的焦点是使用'%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)
我的问题:在将变量aValue(s)组合成字符串时,我非常严格地遵守'...{}'.format(aValue)
(或f'...{aValue}'
)的使用,从而避免使用{{1} (无论我的原因是什么,我们不要在这里进行辩论 - 但这是我希望尽可能保留它的原因,因此我的问题)。
在任何情况下,无论我尝试哪种方式,我都无法使用类似于上述结构的东西来创建将jsonData存储到mySql数据库中的东西,并使用%s
(无论以何种形式或形式)代替'...{}'.format()
。例如,我(在许多迭代中)尝试了
%s
但无论我如何扭转它,我都会遇到以下错误:
ProgrammingError:1064(42000):您的SQL语法有错误;检查与MySQL服务器版本对应的手册,以便在第1行的'[some_content_from_jsonData})附近使用正确的语法
现在我的问题:
1)有没有办法避免在这里使用%s,我错过了?
2)如果没有,为什么?是什么让这变得不可能?它是insert_statement = "INSERT INTO table (id_field, json_data_field) VALUES ({}, {})".format(1, jsonData)
cursor.execute(insert_statement)
函数,还是它是一个JSON对象,还是完全不同的东西? cursor.execute()
不能做{}.format()
可以做的所有事情吗?
答案 0 :(得分:3)
首先:绝对不要将您的数据直接插入您的查询字符串中
在MySQL查询字符串中使用%s
与在python字符串中使用它不同。
在python中,您只需格式化字符串,'hello %s!' % 'world'
变为'hello world!'
。在SQL中,%s
信号参数插入。这会将您的查询和数据分别发送到服务器。您也不受此语法的约束。 python DB-API规范为此指定了更多样式:DB-API parameter styles (PEP 249)。与将数据直接插入查询字符串相比,这有几个优点:
假设您有查询通过密码验证用户。您可以使用以下查询执行此操作(当然,您通常会对密码进行加密和哈希,但这不是此问题的主题):
SELECT 1 FROM users WHERE username='foo' AND password='bar'
构建此查询的简单方法是:
"SELECT 1 FROM users WHERE username='{}' AND password='{}'".format(username, password)
但是,如果有人输入' OR 1=1
作为密码会发生什么。格式化的查询将成为
SELECT 1 FROM users WHERE username='foo' AND password='' OR 1=1
将继续返回1.使用参数插入时:
execute('SELECT 1 FROM users WHERE username=%s AND password=%s', username, password)
这种情况永远不会发生,因为查询将由服务器单独解释。
如果使用不同的数据多次运行相同的查询,则使用格式化查询和参数插入之间的性能差异可能很大。使用参数插入,服务器只需编译一次查询(因为它每次都是相同的)并使用不同的数据执行它,但是使用字符串格式化,它将不得不一遍又一遍地编译它。
答案 1 :(得分:2)
除了上面所说的,我想补充一些我没有立即理解的细节,其他(像我这样的新手;))也可能会有所帮助:
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,))
注意在初始sql语法定义中使用.format以及在execute函数中使用(condition_value,)。