python在mysq中插入和检索二进制数据

2024-05-15 05:53:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用MySQLdb包与MySQL交互。我很难得到正确的类型转换。

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

我正在使用以下架构:

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;

然后使用以下代码在表中创建新行:

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()
)

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

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

然后查询返回空结果。

任何帮助都将不胜感激。另外,顺便提一下,将unix纪元日期存储为整数还是时间戳更好?

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

多谢!@


Tags: 数据idaddeddatadateuuidtimecreate
2条回答

一个提示:您应该能够调用uuid.uuid4().bytes来获取原始数据 字节。至于时间戳,如果要执行时间/日期操作 在SQL中,处理真正的时间戳类型通常更容易。

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

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\xb2O@\xbb\xa27h\xcd<B\xda'
selecting '\xac\xc9,jn\xb2O@\xbb\xa27h\xcd<B\xda'
2 acc92c6a6eb24f40bba23768cd3c42da

为了补充现有的答案,在处理查询中的二进制字符串时,还存在以下警告问题:

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都支持它。

相关问题 更多 >

    热门问题