2011-03-09 76 views
5

我正在使用MySQLdb包与MySQL进行交互。我无法获得正确的类型转换。python插入和检索到MySQL的二进制数据

我正在使用一个16字节的二进制uuid作为表的主键,并且有一个保存zlib压缩的json信息的mediumblob。

我用下面的模式:

data = zlib.compress(json.dumps({'hello':'how are you :D'}) 
row_id = uuid.uuid(4).hex 
added_id = cursor.execute(' 
    INSERT INTO repositories (id, data, create_date, update_date) 
    VALUES (%s, %s, %s, %s)', 
    binascii.a2b_hex(row_id), 
    data, 
    time.time(), 
    time.time() 
) 

然后检索我使用类似的查询数据:

CREATE TABLE repositories (
    added_id int auto_increment not null, 
    id binary(16) not null, 
    data mediumblob not null, 
    create_date int not null, 
    update_date int not null, 
    PRIMARY KEY (added_id), 
    UNIQUE(id) 
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ENGINE=InnoDB; 

然后我用下面的代码在表中创建一个新行:

query = cursor.execute('SELECT added_id, id, data, create_date, update_date ' \ 
    'FROM repositories WHERE id = %s', 
    binascii.a2b_hex(row_id) 
) 

然后查询返回一个空结果。

任何帮助,将不胜感激。此外,另外,将unix时期作为整数或TIMESTAMP存储会更好吗?

注意:我没有问题插入数据,只是试图从数据库中检索它。该行存在于我通过mysqlclient检查时。 !

非常感谢@

回答

7

一个建议:你应该能够调用uuid.uuid4().bytes,以获得原始 字节。至于时间戳,如果您想在SQL中执行时间/日期操作 ,处理真正的TIMESTAMP类型通常更容易。

我创建了一个测试表,尝试重现您所看到的:

CREATE TABLE xyz (
    added_id INT AUTO_INCREMENT NOT NULL, 
    id BINARY(16) NOT NULL, 
    PRIMARY KEY (added_id), 
    UNIQUE (id) 
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ENGINE=InnoDB; 

我的脚本是能够插入和查询使用二场为没有问题 关键的行。也许你不正确地获取/迭代游标返回的结果 ?

import binascii 
import MySQLdb 
import uuid 

conn = MySQLdb.connect(host='localhost') 

key = uuid.uuid4() 
print 'inserting', repr(key.bytes) 
r = conn.cursor() 
r.execute('INSERT INTO xyz (id) VALUES (%s)', key.bytes) 
conn.commit() 

print 'selecting', repr(key.bytes) 
r.execute('SELECT added_id, id FROM xyz WHERE id = %s', key.bytes) 
for row in r.fetchall(): 
    print row[0], binascii.b2a_hex(row[1]) 

输出:

% python qu.py  
inserting '\x96\xc5\xa4\xc3Z+L\xf0\x86\x1e\x05\xebt\xf7\\\xd5' 
selecting '\x96\xc5\xa4\xc3Z+L\xf0\x86\x1e\x05\xebt\xf7\\\xd5' 
1 96c5a4c35a2b4cf0861e05eb74f75cd5 
% python qu.py 
inserting '\xac\xc9,jn\[email protected]\xbb\xa27h\xcd<B\xda' 
selecting '\xac\xc9,jn\[email protected]\xbb\xa27h\xcd<B\xda' 
2 acc92c6a6eb24f40bba23768cd3c42da 
+0

就像随访;我使用Tornado数据库类作为MySQLdb的一个很好的方便包装,当你在连接对象上使用.get()调用时,它不适用于SELECT,但是它具有正确的.query()或.execute() 。 –

2

以补充现有的答案,用二进制字符串中查询交易时也有一个问题,以下警告:

Warning: (1300, "Invalid utf8 character string: 'ABCDEF'") 

它是由以下转载:

cursor.execute(''' 
    CREATE TABLE `table`(
     bin_field` BINARY(16) NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
''') 

bin_value = uuid.uuid4().bytes 
cursor.execute('INSERT INTO `table`(bin_field) VALUES(%s)', (bin_value,)) 

只要MySQL发现查询中的字符串字面值对当前的character_set_connection无效,它就会发出警告。有几种解决方案,以它:

  1. 明确设置_binarycharset literal

    INSERT INTO `table`(bin_field) VALUES(_binary %s) 
    
  2. 手动构造查询与hexadecimal literals

    INSERT INTO `table`(bin_field) VALUES(x'abcdef') 
    
  3. 变化connection charset如果你只使用二进制字符串工作

欲了解更多详情,请参阅MySQL Bug 79317

更新

由于@charlax指出,有binary_prefix标志,它可以传递给连接的初始化器插argumetns时自动在前面加上前缀_binary。它受到最近版本mysql-clientpymysql的支持。

+0

您也可以使用'binary_prefix = True'作为连接选项。请参阅https://bitbucket.org/zzzeek/sqlalchemy/issues/3804/invalid-utf8-character-string-warning-on – charlax