2011-03-09 43 views
5

MySQLとのやりとりにMySQLdbパッケージを使用しています。適切な型変換ができない。Pythonでバイナリデータをmysqlに挿入して取得する

私はテーブルのプライマリキーとして16バイトのバイナリuuidを使用していますが、zlib圧縮されたjson情報を保持する中くらいの大きさのブロブを持っています。

私は、次のスキーマを使用しています:私は類似したクエリを使用し、データを取得するために、次に

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 Database Classを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,)) 

クエリの文字列リテラルが現在のcharacter_set_connectionに対して有効でないとMySQLが判断すると、警告が出力されます。それにはいくつかの解決策があります。

  1. が明示的にあなただけのバイナリ文字列で作業している場合は変更connection charsethexadecimal literals

    INSERT INTO `table`(bin_field) VALUES(x'abcdef') 
    
  2. でクエリを構築手動_binarycharset literal

    INSERT INTO `table`(bin_field) VALUES(_binary %s) 
    
  3. を設定しました

詳細はMySQL Bug 79317を参照してください。

更新

@charlaxが指摘したように、argumetnsを補間するときに自動的に_binary接頭辞を付加するために、接続の初期化子に渡すことができbinary_prefixフラグがあります。最近のバージョンのmysql-clientpymysqlでサポートされています。

+0

'binary_prefix = True'を接続オプションとして使用することもできます。 https://bitbucket.org/zzzeek/sqlalchemy/issues/3804/invalid-utf8-character-string-warning-onを参照してください。 – charlax

関連する問題