在 cursor.execute() 中使用 '.format()' 与 '%s' for mysql JSON 字段,Python mysql.connector,
Use of '.format()' vs. '%s' in cursor.execute() for mysql JSON field, with Python mysql.connector,
我的 objective 是使用 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}'
),从而避免使用 %s
(不管我的原因是什么,我们不要在这里争论它们 - 但这是我希望尽可能保留它的方式,因此我的问题)。
在任何情况下,无论我尝试哪种方式,我都无法使用类似于上述结构的东西创建将 json 数据存储到 mySql 数据库中的东西,并使用 '...{}'.format()
(以任何形状或形式)而不是 %s
。例如,我(在许多迭代中)尝试过
insert_statement = "INSERT INTO table (id_field, json_data_field) VALUES ({}, {})".format(1, jsonData)
cursor.execute(insert_statement)
但无论我怎么转动它,我总是得到以下错误:
ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[some_content_from_jsonData})]' at line 1
现在我的问题:
1) 有没有办法避免在这里使用我遗漏的 %s?
2) 如果不是,为什么?是什么使这不可能?它是 cursor.execute()
函数,还是它是一个 JSON 对象,还是完全不同的东西? {}.format()
不应该能做到 %s
能做到的一切,甚至更多吗?
首先:切勿将您的数据直接插入查询字符串!
在 MySQL 查询字符串中使用 %s
与在 python 字符串中使用它不同。
在 python 中,您只需格式化字符串,'hello %s!' % 'world'
就变成了 'hello world!'
。在 SQL 中,%s
表示参数插入。这会将您的查询和数据分别发送到服务器。您也不受此语法的约束。 python DB-API 规范为此指定了更多样式:DB-API parameter styles (PEP 249)。与将数据直接插入查询字符串相比,这有几个优点:
防止SQL注入
假设您有一个通过密码对用户进行身份验证的查询。您可以使用以下查询来做到这一点(当然您通常会对密码进行 salt 和散列处理,但这不是本问题的主题):
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
which will allways return 1. 使用参数插入时:
execute('SELECT 1 FROM users WHERE username=%s AND password=%s', username, password)
这永远不会发生,因为查询将由服务器单独解释。
性能
如果您 运行 多次使用不同的数据进行相同的查询,则使用格式化查询和参数插入之间的性能差异可能会很大。使用参数插入,服务器只需要编译一次查询(因为每次都是一样的)并用不同的数据执行它,但是使用字符串格式化,它将不得不一遍又一遍地编译。
除了上面所说的,我想补充一些我没有立即理解的细节,其他(像我这样的新手;))可能也会觉得有用:
1) "parameter insertion" 仅适用于值 ,它不适用于 table 名称、列名等 - 对于那些, 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 并在执行函数中使用 (condition_value,)。
我的 objective 是使用 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}'
),从而避免使用 %s
(不管我的原因是什么,我们不要在这里争论它们 - 但这是我希望尽可能保留它的方式,因此我的问题)。
在任何情况下,无论我尝试哪种方式,我都无法使用类似于上述结构的东西创建将 json 数据存储到 mySql 数据库中的东西,并使用 '...{}'.format()
(以任何形状或形式)而不是 %s
。例如,我(在许多迭代中)尝试过
insert_statement = "INSERT INTO table (id_field, json_data_field) VALUES ({}, {})".format(1, jsonData)
cursor.execute(insert_statement)
但无论我怎么转动它,我总是得到以下错误:
ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[some_content_from_jsonData})]' at line 1
现在我的问题:
1) 有没有办法避免在这里使用我遗漏的 %s?
2) 如果不是,为什么?是什么使这不可能?它是 cursor.execute()
函数,还是它是一个 JSON 对象,还是完全不同的东西? {}.format()
不应该能做到 %s
能做到的一切,甚至更多吗?
首先:切勿将您的数据直接插入查询字符串!
在 MySQL 查询字符串中使用 %s
与在 python 字符串中使用它不同。
在 python 中,您只需格式化字符串,'hello %s!' % 'world'
就变成了 'hello world!'
。在 SQL 中,%s
表示参数插入。这会将您的查询和数据分别发送到服务器。您也不受此语法的约束。 python DB-API 规范为此指定了更多样式:DB-API parameter styles (PEP 249)。与将数据直接插入查询字符串相比,这有几个优点:
防止SQL注入
假设您有一个通过密码对用户进行身份验证的查询。您可以使用以下查询来做到这一点(当然您通常会对密码进行 salt 和散列处理,但这不是本问题的主题):
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
which will allways return 1. 使用参数插入时:
execute('SELECT 1 FROM users WHERE username=%s AND password=%s', username, password)
这永远不会发生,因为查询将由服务器单独解释。
性能
如果您 运行 多次使用不同的数据进行相同的查询,则使用格式化查询和参数插入之间的性能差异可能会很大。使用参数插入,服务器只需要编译一次查询(因为每次都是一样的)并用不同的数据执行它,但是使用字符串格式化,它将不得不一遍又一遍地编译。
除了上面所说的,我想补充一些我没有立即理解的细节,其他(像我这样的新手;))可能也会觉得有用:
1) "parameter insertion" 仅适用于值 ,它不适用于 table 名称、列名等 - 对于那些, 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 并在执行函数中使用 (condition_value,)。