UTF8轉換JDBC似乎當被問及從包含未定義LATIN1代碼頁字符LATIN1列讀取插入UTF8替換字符。這種行爲與MySQL的內部函數不同。怪誕LATIN1在JDBC
字符編碼是我一直停留在過去一週兔子洞,並在不產生100個明顯答案的利益,我將演示最新一對夫婦的代碼示例發生。
MySQL的:
[[email protected] ~]$ echo 'SELECT CONVERT(UNHEX("81") using latin1);' | mysql --init-command='set names latin1' | tail -1| hexdump -C
00000000 81 0a |..|
00000002
[[email protected] ~]$ echo 'SELECT CONVERT(UNHEX("81") using latin1);' | mysql --init-command='set names utf8' | tail -1| hexdump -C
00000000 c2 81 0a |...|
00000003
這是很明顯的,並完全按預期工作。 0x81
是一個未定義的latin1代碼點。它以UTF8中的\u0081
或以十六進制「在磁盤上」表示爲c2 81
。現在
古怪來自JDBC
,拿這個常規例子:
@GrabConfig(systemClassLoader=true)
@Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
import groovy.sql.Sql
sql = Sql.newInstance('jdbc:mysql://localhost/test', 'root', '', 'com.mysql.jdbc.Driver')
sql.eachRow('SELECT CONVERT(UNHEX("C281") using utf8) as a;') { println "$it.a --" }
這個查詢的輸出是兩個字節,c2 81
預期。它很容易理解這裏發生了什麼。 Mysql連接默認爲UTF8。 unhexxed列也轉換爲UTF8(無編碼,因爲源是二進制的,CONVERT()之後的數據仍然是c2 81
)。
現在考慮這種情況。連接仍然是UTF8,就像JDBC默認的一樣。我們將0x81字節轉換爲latin1,所以希望mysql能夠像上面bash例子中那樣將它轉換爲c2 81
。
@GrabConfig(systemClassLoader=true)
@Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
import groovy.sql.Sql
sql = Sql.newInstance('jdbc:mysql://localhost/test', 'root', '', 'com.mysql.jdbc.Driver')
sql.eachRow('SELECT CONVERT(UNHEX("81") using latin1) as a;') { println "$it.a --" }
運行此與groovy latin1_test.groovy | hexdump -C
產生這樣的:
00000000 ef bf bd 0a |....|
00000004
ef bf bd
是UTF8替換字符。在utf8轉換失敗時使用的字符。
爲什麼Java的執行字符集轉換,當MySQL可以做它與集名稱utf8 ?.我遺憾地沒有訪問這裏的Java代碼(groovy只是爲了測試),因爲問題來自Sqoop,一個mysql到hadoop導入應用程序 –
嗯,你要求打印內容,因此它必須做解碼,對吧? – fge
數據是否可以用二進制打印(或者是什麼使它不被修改/轉換)。它只是,c2 81是一個有效的UTF8代碼點,並且mysql將任何latin1代碼點(00到FF)轉換爲U + 0000到U + 00FF,這可能是錯誤的,但至少它的可逆 –