mysql-python排序规则问题:如何强制unicode数据类型?

时间:2012-03-01 19:12:05

标签: python mysql mysql-python

出于某些目的,我必须在数据库中将字段排序从utf8_unicode_ci更改为utf8_bin。事实证明,这种变化会导致python的数据类型发生变化。

问题是如何强制mysql-python将unicode对象返回到python

这是一个显示问题的示例(显式字符集强制use_unicode = 1):

>>> con = MySQLdb.connect(..., charset='utf8')
>>> c = c.cursor()
>>> c.execute('SELECT %s COLLATE utf8_bin', u'м')
1L
>>> c.fetchone()
('\xd0\xbc',)
>>> c.description
(("'\xd0\xbc' COLLATE utf8_bin", 253, 2, 3, 3, 31, 0),)


>>> c.execute('SELECT %s COLLATE utf8_unicode_ci', u'м')
1L
>>> c.fetchone()
(u'\u043c',)
>>> c.description
(("'\xd0\xbc' COLLATE utf8_unicode_ci", 253, 2, 3, 3, 31, 0),)

在我的数据库中,字段的类型为VARCHAR,但在更改后,它们的行为类似于BINARY,这不是我想要的。

2 个答案:

答案 0 :(得分:2)

事实证明,问题相当尴尬。简而言之,MySQL string datatypes中的大多数变量和物种都映射到MySQL接口中的单个数据类型,并附加了一个BINARY标志。

因此,MySQL的VARCHARVARBINARY和字符串文字映射到列类型定义中的相同MySQLdb.constants.FIELD_TYPE.VAR_STRING类型,但在类型时有一个额外的MySQLdb.constants.FLAG.BINARY标志是VARBINARY或与*_bin归类整理的字符串。

即使有MySQLdb.constants.FIELD_TYPE.VARCHAR类型,我也未能找到它的使用时间。正如我所说,MySQL VARCHAR列映射到FIELD_TYPE.VAR_STRING

如果您的应用程序使用真正的二进制字符串(例如,您存储图像并使用与文本相同的连接来获取它们),则解决方案变得相当脆弱,因为它假定将所有二进制字符串解码为unicode。虽然,它有效。

正如docs官方所述:

  

因为MySQL将所有数据作为字符串返回,并希望您自己转换它。这对屁股来说真的很痛苦,但事实上,_mysql可以为你做到这一点。 (并且MySQLdb会为您执行此操作。)要完成自动类型转换,您需要创建一个类型转换器字典,并将其作为 conv 关键字参数传递给connect()。

在实践中,屁股的真正痛苦可能是构建自己的转换器字典的过程。但是您可以从MySQLdb.converters.conversions导入默认值并对其进行修补,甚至可以在Connection的实例上进行修补。诀窍是删除FLAG.BINARY标志的特殊转换器,并为所有情况添加解码器。如果您为charset明确指定了MySQLdb.connect参数,则会强制use_unicode=1参数,这会为您添加解码器,但您可以自行完成:

>>> con = MySQLdb.connect(**params)
>>> con.converter[FIELD_TYPE.VAR_STRING]
[(128, <type 'str'>), (None, <function string_decoder at 0x01FFA130>)]
>>> con.converter[FIELD_TYPE.VAR_STRING] = [(None, con.string_decoder)]
>>> c = con.cursor()
>>> c.execute("SELECT %s COLLATE utf8_bin", u'м')
1L
>>> c.fetchone()
(u'\u043c',)

如果需要,您可能需要对FIELD_TYPE.STRING进行相同的黑客攻击。

另一个解决方案是将显式use_unicode=0传递给MySQLdb.connect并在代码中进行所有解码,但我不会。

希望,这可能对某人有用。

答案 1 :(得分:1)

在低级别使用Mysql-Python是一个很大的变化,但我认为更好的想法是使用sqlalchemy之类的东西而不是直接使用db-api,然后你可以使用例如types.Unicode并且知道它正在执行db-api的unicode支持所需的内容

在你跳过我没有直接回答这个问题之前,请考虑一下:mysql-python又称MySQLdb只是MySQL的几个db-api之一。新版本可能会继续支持MySQLdb,但有些情况(例如转移到python 3x,或者你无法安装二进制模块的主机)可能会迫使你在将来使用其他东西,例如:为oursqlmyconnpy。制作sqlalchemy的人已经付出了很多努力来支持多个db-api,而在mysql-python的情况下,他们甚至在过去遇到了严重的错误。使用sqlalchemy,更改为不同的db-api就像更改连接URL一样简单,它可以确保处理数据类型强制的任何内容都按照您的预期处理。

那就是说,为了利用它,你需要根据sqlalchemy的模式定义你的表并使用他们的查询API,但你会得到很多。