2016-02-02 69 views
2

奇怪的結果在這裏是scenario-與字符編碼

  • DB2數據庫是主機系統上(Z/OS)
  • 的Web服務器上的USS(z/OS的Unix的一部分)上運行,運行Java代碼與Spring JDBC
  • 我們用測試的瀏覽器和Windows 7客戶端程序運行(默認編碼爲Windows-1252)

我們有一個包含西班牙字符(U)的字符串,它存儲在數據庫usi中ng Spring的JDBCTemplate,所以基本上是JDBC。

  • 當使用JDBC客戶端(Squirrel,用Java編寫)查詢時,它顯示爲其他內容(ú)。
  • 當使用JDBC程序進行查詢並將結果打印爲字符串時,它顯示爲其他內容(ú)。
  • 當使用示例JDBC程序查詢並將結果打印爲UTF-8編碼的字符串[new String(str,「UTF-8」)]時,它會正確顯示(ú)。
  • 使用此-Dfile.encoding = utf-8啓動使用UTF-8編碼的JVM時,在上述兩種情況下結果都會打印爲別的(ú)。
  • 運行應用程序前端的瀏覽器也將其顯示爲ú,但HTML的內容標頭設置爲UTF-8。

在這個階段,我有點迷茫,有這些問題 -

  • 如果打印在UTF-8格式的字符串具體工作中,當JVM啓動用UTF爲什麼沒有工作-8編碼。
  • 問題實際發生在哪一層,數據庫還是JVM?

我該怎麼做才能解決在應用程序級別而不是在列級?

任何指針都會有幫助。

+0

您使用的String的雙參數構造函數將字節數組作爲第一個參數。在調用新的String(str,「UTF-8」)之前,如何將字符串結果從數據庫轉換爲字節? –

+0

@Daniel:我對從數據庫中獲得的字符串調用str.getBytes()。 – User2709

+1

在JDBC中,你必須指定編碼你已經完成了嗎? –

回答

4

您看到的效果都可以通過假設數據以UTF-8字節寫入數據庫的假設來解釋,但數據庫認爲這些字節是其他字符集(ISO-LATIN-1或Windows-1252),然後在讀取數據時,返回的字符串是解釋爲ISO-LATIN-1或相關字符集的字節。

UTF-8中的字符ú是兩個字節0xC3 0xBA。當這些字節被解釋爲ISO-LATIN-1或者win-1252時,你會得到兩個字符ú

用UTF-8編寫的兩個字符ú是四個字節0​​xC3 0x83 0xC2 0xBA。當這四個字節被解釋爲ISO-LATIN-1(或win-1252)時,你會得到四個字符ú

(WINDOWS-1252和ISO-LATIN-1發生在對有問題的所有字節/字符的同意,因此,從證據看,我不能告訴他們之間的區別)

發生了什麼事給你,我相信是這樣的:

  1. 的JDBC客戶端查詢數據庫,並取回含有從數據庫中兩個字符ú的字符串。

  2. 當JVM打印結果到Windows 7的儲物箱,如果開始-Dfile.encoding=utf-8,將其發送到扶手箱,以表示雙贏1252字符串所需的字節數。如果啓動該選項的JVM ,則它將以UTF-8格式表示字符串所需的字節數發送到控制檯框。

  3. 您的Windows 7控制檯框設置爲窗口1252,並顯示通過解釋字節的java什麼的Java打印出根據窗口1252

  4. 當你調用.getBytes()不帶參數的,你把它使用JVM的默認編碼將字符串轉換爲字節。因此,如果默認JVM編碼爲UTF-8,則new String(str.getBytes(), "UTF-8")將導致相同的字符串,並且如果默認編碼與UTF-8不同,則只能導致實際發生的情況。

這就解釋了所有你所提交的證據:通過JDBC檢索到的Java字符串包含字符ú,然後當一個非UTF-8 JVM試圖打印此控制檯中,這是打印爲ú 。當utf-8 JVM嘗試將此字符串打印到控制檯盒時,它會打印四個字節0​​xC3 0x83 0xC2 0xBA,並且控制檯將其解釋爲四個字符ú。當一個java web服務器試圖將這個字符串發送回瀏覽器時,它會這樣做 - 瀏覽器看到的是java應用程序從JDBC接收到的內容。

首先要檢查的是Spring JDBCTemplate正確接收數據並正確寫入數據庫。你可以讓Spring記錄它從瀏覽器接收到的內容,並確保瀏覽器發送UTF-8,並且Spring知道瀏覽器正在發送UTF-8? (你可能想要檢查的一件事是記錄接收到的字符串以及每個字段中字符串的長度,這可以讓你知道是否正確解釋爲UTF-8)

假設數據越來越到正確的數據庫,就像你說的,你不能讓在數據庫方面的變化,並希望從應用端純粹的變化,你可以做到這一點從JDBC收到的每個字符串:

new String(str.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8) 

無論JVM的默認編碼是什麼,這應該會將您的字符串轉換回您想要的。

爲了將來的參考,從windows命令行運行一個帶有-Dfile.encoding=utf-8的jvm通常需要先更改控制檯上的代碼頁,以便正確查看內容。 (這可以通過命令chcp 65001來完成,只要記住在運行沒有設置該選項的JVM命令前使用chcp 1252即可)

+0

我認爲你的觀察是絕對有道理的。我非常確定數據庫不會將它視爲UTF-8,因此我會嘗試確定數據庫可以識別的編碼類型,以及瀏覽器是否發送正確的數據。感謝您的好解釋。 – User2709