記一次伺服器遷移第一篇-----JDK時區TimeZone與作業系統不一致

13811135929發表於2017-04-11
【背景】一臺Windows伺服器的遷移工作,涉及作業系統、應用以及資料庫,其中:
  1.作業系統由Windows Server 2003--->Windows Server 2008
  2.資料庫:Oracle 10.2.0.4--->Oracle 11.2.0.3
  3.應用遷移本在本篇博文的討論範圍
 之前方案經過幾輪評審,該改進地方修改了多次。測試環境也進行了多次測試。自認為在生產環境變更會一切順利,萬無一失,自信滿滿,但很快被現實狠狠的抽了一巴掌。經梳理,碰到的問題主要有兩個,以下計劃分兩篇進行總結歸納,若有錯誤,歡迎各位大神指正。
  伺服器遷移完成後,啟動定時作業出現了一個異常現象,該作業理應生成T-1日檔案不知為何檔案變成了T-2日。出現問題的時候,開發人員並不在現場,本著先不麻煩別人的原則。第一反應就是有可能是資料庫遷移造成的。
 為排除資料庫方面的問題,我們查詢了常用時間變數sysdate,systimestamp,localtimestamp以及current_timestamp,發現輸出都和自然時間相同。

點選(此處)摺疊或開啟

  1. SELECT sysdate FROM dual;
  2. SYSDATE
  3. -----------------
  4. 20170409 07:56:19

  5. SELECT systimestamp FROM dual;
  6. SYSTIMESTAMP
  7. ---------------------------------------------------------------------------
  8. 09-APR-17 07.56.52.311941 AM +08:00

  9. SELECT localtimestamp FROM dual;
  10. LOCALTIMESTAMP
  11. ---------------------------------------------------------------------------
  12. 09-APR-17 07.59.04.507493 AM

  13. SELECT current_timestamp FROM dual;
  14. CURRENT_TIMESTAMP
  15. ---------------------------------------------------------------------------
  16. 09-APR-17 07.59.17.414758 AM +08:00
  那看來和資料庫無關?正在猶豫的時候,再次啟動定時作業的時候發現執行結果正確了,生成了T-1日的檔案,且檔案內容也無異常。奇怪,不過定時作業總算執行正常了,由於有其他事情要忙,這個事情就沒有再深入分析。
  悲催的是,第二天問題又重現了,且情況和前一天幾乎一樣:剛開始作業異常,分析了一段時間,再次重啟作業又正常了。什麼情況?看來這個不是偶發現象,要仔細深入的研究個明白了。在分析過程我們發現了一個非常有趣的現象:作業若在8點之前執行就會異常,一過8點作業執行正常。難道是時區造成的?不對啊,前面已經查詢已經確認了,資料庫時區和時間都沒問題。為了進一步確認資料庫時區正常,還是檢視一下dbtimezone變數吧。

點選(此處)摺疊或開啟

  1. SELECT dbtimezone FROM dual;
  2. DBTIME
  3. ------
  4. +08:00
   基本排查了資料庫的原因造成的,作為DBA的我不禁鬆了一口氣。下面的分析可以放鬆些了,不用提心吊膽啦,哈哈。既然懷疑時區造成的,那看看是不是作業系統的時區問題。但非常遺憾經確認作業系統時區設定也是正確的 :東8區。經過一番確認和排查,始終未發現伺服器、資料庫引數設定的問題,找開發要程式碼吧。程式碼非常簡單,擷取部分有用內容如下:

點選(此處)摺疊或開啟

  1. String strCreDate = new java.sql.Date(new java.util.Date().getTime()-86400000).toString();
   具體生成T-1日還是T-2日的檔案,由strCreDate變數決定的。那看來變數strCreDate的值有問題。我們分別做了一組實驗:8點前strCreDate的值為T-2,但8點後該值就變成了T-1.為清楚的看到JDK時區情況,寫了一個非常簡單HelloWorld程式碼,如下: 

點選(此處)摺疊或開啟

  1. import java.util.TimeZone;
  2. import java.sql.Date;
  3. public class HelloWorld {
  4.     public static void main(String[] args) {
  5.     System.out.print("當前的預設時區為");
  6.     System.out.println(TimeZone.getDefault());                            //輸出當前預設時區 
  7.     final TimeZone zone = TimeZone.getTimeZone("GMT+8");                  //獲取中國時區
  8.     TimeZone.setDefault(zone);                                            //設定時區
  9.     System.out.println(TimeZone.getDefault());                            //輸出驗證 
  10.     }
  11. }
   第一個輸出結果為:

 第二個輸出結果為:

    發現了什麼了嗎?雖然作業系統的時區為東8區,但是jdk獲取的時區不是東8區,缺是UTC,因此造成了差8個小時的現象,即8點前作業異常,8點後作業又正常了。問題已經找出來了,就是jdk的問題,解決方案就迎刃而解了。具體辦法如下:
 在下面四個目錄(\jre6\lib\zi\Etc、Java\jre6\lib\zi、Java\jdk1.6.0_18\jre\lib\zi\Etc、Java\jdk1.6.0_18\jre\lib\zi)下找到GMT檔案備份一下,然後複製一份GMT-8並重新命名為GMT,複製完畢,重新執行一下java程式問題即可解決!
    按照上述方法處理後,再次執行HelloWorld命令,輸出正常了。次日觀察作業也正常了。至此問題處理完畢。

【總結】
   分析整個問題的過程,也在網上找了大量的資料,發現JAVA程式遷移很容易造成時區錯誤,時間差8個小時的問題。因此後續java程式遷移且牽扯到時間的情況一定注意。


 
 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29827284/viewspace-2137006/,如需轉載,請註明出處,否則將追究法律責任。

相關文章