我尝试使用 pymysql 插入 Unicode 值,但在 INSERT
查询中出现语法错误。但是当我用 utf8 编码值时它工作得很好,这是我不想要的。
这是我的代码:
from pymysql.cursors import *
import pymysql
from collections import OrderedDict
import datetime
class OrderedDictCursor(DictCursorMixin, Cursor):
dict_type = OrderedDict
conn1 = pymysql.connect(host='127.0.0.1',
port=3306,
user='root',
passwd='pwd',
db='test',
charset='utf8',
use_unicode=True,
autocommit=True)
cursor1 = conn1.cursor(OrderedDictCursor)
odict = OrderedDict([(u'id', 374), (u'title', u'Chapter 4'), (u'intro_list', u'Objective:\r\n\r\n* Exit any mininet launch done earlier using \u201cmn \u2013c\u201d\r\n'), (u'solution', u'%%beginpanel%%\r\n\r\n## 1. net\r\n\r\n```\r\nmn -c\r\n```\r\n\r\n \u201cCTRL+C\u201d \r\n\r\n%%endpanel%%\r\n'), (u'created', datetime.datetime(2017, 3, 9, 7, 58, 7)), (u'modified', datetime.datetime(2017, 8, 28, 4, 58, 15))])
cols = odict.keys()
vals = odict.values()
cursor1.execute("INSERT INTO %s (%s) VALUES (%s)" % ("test1", ",".join(cols), (str(vals)[1:-1])))
这会引发语法错误,
pymysql.err.ProgrammingError: (1064, u"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 ''Chapter 4', u'Objective:\r\n\r\n* Exit any mininet launch done earlier using \u' at line 1")
当我使用 utf8 对值进行编码时,插入成功,但这也会对\u201cmn\u2013c\u201d 等值进行编码,而我的应用程序无法将其解码回来。
我需要一个解决方案来将我的 unicode 值按原样插入到我的 MySQL 数据库中。
请大家帮忙。
最佳答案
"INSERT INTO %s (%s) VALUES (%s)" % ("test1", ",".join(cols), (str(vals)[1:-1]))
这是根据上面的数据生成的查询字符串:
INSERT INTO test1 (id,title,intro_list,solution,created,modified)
VALUES (
374,
u'Chapter 4',
u'Objective:\\r\\n\\r\\n* Exit any mininet launch done earlier using \\u201cmn \\u2013c\\u201d\\r\\n',
u'%%beginpanel%%\\r\\n\\r\\n## 1. net\\r\\n\\r\\n```\\r\\nmn -c\\r\\n```\\r\\n\\r\\n \\u201cCTRL+C\\u201d \\r\\n\\r\\n%%endpanel%%\\r\\n',
datetime.datetime(2017, 3, 9, 7, 58, 7),
datetime.datetime(2017, 8, 28, 4, 58, 15)
)
调用str()
您的值列表上正在创建值列表的 Python 表示形式。值文字的 Python 语法与 SQL 语法非常不同,因此只需用 [1:-1]
切掉列表 repr 的方括号即可。与执行此 SQL 相差甚远:
-
u'...'
不是有效的 SQL 字符串文字; - 即使您编码为 UTF-8,也会得到 Python 2 字节字符串文字
'...'
,该语法在几个方面与 SQL 不同,因此它仅有时有效; - 例如反斜杠语法
\\r
不是 SQL 字符串文字中的转义; -
datetime.datetime
是一种 Python 数据类型,而不是 SQL 数据类型。
主要错误是尝试将您的值包含在查询字符串本身中。即使您手动单独格式化这些值,您仍然会面临语法/转义规则错误并最终出现 SQL 注入(inject)安全漏洞的风险。
相反,您应该使用参数化查询,将第二个参数中的参数值列表传递给 execute()
:
cols_str = ', '.join(cols)
params_str = ', '.join(['%s'] * len(vals))
query = 'INSERT INTO %s (%s) VALUES (%s)' % (table_name, cols_str, params_str)
cursor.execute(query, vals)
注意:与 cols_str
不同,%s
在params_str
是一个真正的百分号-然后-s 序列,而不是被替换掉的东西。它被传递到 execute()
作为 vals
中相应参数值的占位符.
参数占位符看起来与字符串格式占位符相同,这非常令人困惑,但这就是 paramstyle
pymysql选择。其他DBAPI模块有所不同。
也没有解决:我们没有转义表或列名称,如果使用 SQL 关键字,就会出错,如果这些名称来自不受信任的输入,也会导致 SQL 注入(inject)漏洞,尽管这种情况要少得多比值(value)观更常见。通常,为了转义模式名称,您可以将它们用双引号以及双引号和双引号括起来,但 MySQL 可能需要反引号,具体取决于它的配置方式。
所有这些复杂性就是为什么最好使用现有的数据访问层来解决这个问题。
I need a solution to insert my unicode values as is into my MySQL database.
除了这里的 DBAPI 层问题之外,您还需要确保您拥有的表/列使用支持所有字符的排序规则进行编码。这里默认-默认设置是创建Latin-1-Swedish表,没用。
您可以包括例如 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
在 CREATE TABLE
中的每个字符串列定义中,或开头 CREATE DATABASE
在创建表之前。
关于python - pymysql插入查询中的Unicode值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48749775/