2011-03-09 55 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