我正在尝试使用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“您的SQL语法有误;请查看与您的MySQL服务器版本相对应的手册,以获取在'第4章,u'目标附近使用的正确语法。Objective:\ r \ n \ r \ n *在行1“处使用\ u'退出任何先前完成的mininet启动)


当我使用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]切下列表代表包装的方括号并不能接近此SQL:


u'...'不是有效的SQL字符串文字;
即使您使用UTF-8进行编码,也因此获得了Python 2字节的字符串文字'...',其语法在某些方面与SQL有所不同,因此有时只能使用;
例如,反斜杠语法\\r不是SQL字符串文字中的转义符;
datetime.datetime是Python数据类型,而不是SQL数据类型。


主要错误是试图将您的值包括在查询字符串本身中。即使您单独手动格式化了这些值,也仍然会冒出错误的确切语法/转义规则并最终导致SQL Injection安全漏洞的风险。

相反,您应该使用参数化查询,将第二个参数中的参数值列表传递给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

参数占位符看起来与字符串格式的占位符看起来很令人困惑,但这是pymysql选择的。其他DBAPI模块是不同的。

还没有解决:我们没有转义表或列的名称,如果使用SQL关键字将它们转义,并且如果这些名称来自不受信任的输入,也会导致SQL注入漏洞,尽管这比它不常见是为了价值观。通常,为了转义模式名称,可以将它们用双引号和双引号和双引号引起来,但是MySQL可能需要反引号,具体取决于其配置方式。

所有这些复杂性就是为什么最好使用现有的数据访问层为您解决这个问题的原因。


  我需要一种解决方案,将unicode值直接插入MySQL数据库。


除了此处的DBAPI层问题外,您还需要确保使用支持所有字符的排序规则对表/列进行编码。这里的默认默认设置是创建Latin-1-Swedish表,这是没有用的。

您可以在创建表之前,将paramstyle包含在CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci中的每个字符串列定义中,或将其包含在初始CREATE TABLE中。

关于python - pymysql中的Unicode值插入查询,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48749775/

10-16 23:18