JDBC中日期時間的處理技巧
基礎知識
Java中用類java.util.Date
對日期/時間做了封裝,此類提供了對年、月、日、時、分、秒、毫秒以及時區的控制方法,同時也提供一些工具方法,比如日期/時間的比較,前後判斷等。
java.util.Date中採用一個long型的數來儲存日期/時間,它表示從格林威治時間1970年1月1日00點00分00秒至今的毫秒數。
JDBC中,在這個類的基礎之上擴充套件了3個類:
java.sql.Date,
java.sql.Time,
java.sql.Timestamp
java.sql.Date
表示日期,只包括年月日;
java.sql.Time
表示時間,只包括時分秒;
java.sql.Timestamp
表示時間戳,包括年月日,時分秒,還有毫秒和納秒;值得注意的是它比java.util.Date
還多了一個納秒。
這3個類分別對應資料庫的3種資料型別:
java.sql.Date
日期(只包括年月日)
java.sql.Time
時間(只包括時分秒)
java.sql.Timestamp
日期/時間(包括年月日,時分秒,還有毫秒和納秒)
處理技巧。
1.對於資料庫種不同的時間型別,要分別採用與之相對應的Java包裝類來存取
日期型別用java.sql.Date
,時間型別用java.sql.Time
,日期/時間型別用java.sql.Timestamp
;
這裡舉個例子:假設要從oracle中獲取系統時間,需要執行sql:select sysdate from dual
ResultSet
獲取查詢結果時,一定要呼叫方法:getTimestamp()
,這樣才可以把年月日時分秒都取出來,呼叫getDate()
只能取出年月日,呼叫getTime()
只能取出時分秒。呼叫getString
也可以取出來,但是存在問題,見技巧2。
2.儘量不要呼叫getString()來獲取日期/時間型別的資料
呼叫getString()
也可以取出時間型別的資料,JDBC在內部將日期/時間轉換為字串;但是這個字串的格式卻取決於資料庫,用Oracle是一種,用Sybase又是一種,mysql又是一種,如果你想相容多種資料庫,還是不要用getString()
的好。
另外,採用字串來儲存時間存在一些問題,還有是效率問題,用getString()
getTimestamp()
只需要做整數的運算和處理;而整數的運算處理一般都比字串處理效率高。
3.如何將JDBC的日期/時間型別轉換為字串
曾經看到過有人這樣寫:
java.sql.Timestamp timeStamp = //通過資料庫訪問獲取到該資料
java.util.Date utilDate = new java.util.Date(timeStamp.getTime());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(utilDate);
這樣也可以達到最終目的,但是有點問題,java.sql.Timestamp
是繼承java.util.Date
的,因此format的時候直接傳入timeStamp
即可,沒有必要臨時建立一個utilDate
。像下面這樣就可以了:
java.sql.Timestamp timeStamp = //通過資料庫訪問獲取到該資料
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(timeStamp);
如果是java.sql.Date
或java.sql.Time
,也是同樣的道理。
4.在做select、update或insert時,如果某個欄位為日期/時間型別,最好用PreparedStatement,而不要採用Statement
經常會看到這樣的程式:
Connection conn;//前面的步驟略
Statement stmt = conn.createStatement();
stmt.execute("insert into tab ( begin_date ) values ( TO_Date( '06/27/2005 12:59:52', 'MM/DD/YYYY HH24:MI:SS'))");
熟悉oracle的人都知道,To_Date
是oracle裡的函式,其他資料庫沒有,即使有也很可能不一樣。那麼這段程式碼只能用在oracle上,如果換成其他資料庫,程式就無法執行了。
如果採用PreparedStatement,程式碼是這樣:
Connection conn;//前面的步驟略
PreparedStatement pstmt = conn.prepareStatement("insert into tab ( begin_date ) values( ?)");
pstmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
pstmt.execute();
可以看出來,這段程式碼與資料庫無關,只要是支援標準sql的資料庫都沒有問題。
客戶是上帝,想用什麼資料庫,我們就得支援什麼資料庫,為了避免以後的麻煩,還是用PreparedStatement
的好。
5.儲存過程的引數,該用日期/時間型別的就要用,不要一味的都採用字串型
儲存過程,只要是日期/時間,都採用字串型別(varchar2或其它)。這樣會造成很多麻煩。
首先,需要約定字串格式,呼叫者和被呼叫者都必須遵循這個格式,這種約定很容易受人為因素影響;
其次,儲存過程中需要對字串做分析,合法性檢查等,增加了編碼的難度和負責度;
再者,這些額外的程式碼,降低的程式的效率,增加了資料庫的負擔。
採用日期/時間型別來作為儲存過程的引數,可以降低編碼的難度,從邏輯上看起來更清晰,而且執行效率高。
在JDBC中採用CallableStatement
來呼叫儲存過程,對日期/時間的輸入和輸出,可以採用setTimestamp,getTimestamp,setDate,getDate,setTime,getTime
。
6.java.sql.Timestamp如何轉換為java.util.Date?
java.sql.Timestamp
是java.util.Date
的子類,不需要做任何轉換直接賦值即可:
java.sql.Timestamp ts;
java.util.Date utilDate;
utilDate = ts;
java.sql.Date
和java.sql.Time
也是一樣的道理。
7.java.util.Date如何轉換為java.sql.Timestamp?
java.util.Date
是java.sql.Timestamp
的父類,不能像技巧6那樣做了。要這樣:
java.sql.Timestamp ts;
java.util.Date utilDate;
ts.setTime(utilDate.getTime());
java.sql.Date
和java.sql.Time
也是一樣的道理。