Tôi tập hợp một số mã JDBC thử nghiệm để tìm ra chính xác những gì sẽ xảy ra. Kết quả thật thú vị. Oracle có ba kiểu dữ liệu có liên quan chặt chẽ: TIMESTAMP
, TIMESTAMP WITH TIME ZONE
và TIMESTAMP WITH LOCAL TIME ZONE
. Tôi lấy chính xác mã đó và chạy nó từ hai hộp khác nhau, một trong múi giờ "America/New_York" và một chạy trên UTC. Cả hai đều nhấn cùng một cơ sở dữ liệu, chạy trong UTC. Tôi đã sử dụng trình điều khiển Oracle 11.2.0.2.0.
- Cột
TIMESTAMP
được đặt thành bất kỳ thời gian cục bộ nào trên máy thực thi mã Java. Không có bản dịch múi giờ nào được thực hiện.
- Cột
TIMESTAMP WITH TIME ZONE
dịch thời gian để bất cứ điều gì múi giờ client JDBC là trong.
- Cột
TIMESTAMP WITH LOCAL TIME ZONE
cũng dịch thời gian để bất cứ điều gì múi giờ client JDBC là trong.
This article, đó là một chút cũ , chỉ ra rằng TIMESTAMP WITH TIME ZONE
là khá nhiều vô ích nếu bạn muốn làm bất cứ điều gì giống như chỉ mục hoặc phân vùng. Tuy nhiên, có vẻ như TIMESTAMP WITH LOCAL TIME ZONE
có thể cực kỳ hữu ích. (Bạn không chắc chắn điều gì sẽ xảy ra nếu bạn thay đổi múi giờ của máy chủ, nhưng có vẻ thông minh về múi giờ địa phương của khách hàng JDBC). Tôi đã không có cơ hội để kiểm tra hành vi lập chỉ mục, v.v. với các kiểu dữ liệu này.
Dán trong lớp mẫu của tôi dưới đây nếu bạn muốn tái tạo các thử nghiệm của mình trong môi trường của bạn.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Date;
// create table x_tst_ts_tab(
// os_name varchar(256)
// ts timestamp,
// ts_with_tz timestamp with time zone,
// ts_with_local_tz timestamp with local time zone
//)
class TSTest {
public static final void main(String[] argv) throws Exception {
Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection(
"your_connection_string",
"your_user_name",
"your_password");
try {
// Insert some data
Date nowDate = new Date();
Timestamp nowTimestamp = new Timestamp(nowDate.getTime());
PreparedStatement insertStmt = conn.prepareStatement(
"INSERT INTO x_tst_ts_tab"
+ " (os_name, ts, ts_with_tz, ts_with_local_tz)"
+ " VALUES (?, ?, ?, ?)");
try {
insertStmt.setString(1, System.getProperty("os.name"));
insertStmt.setTimestamp(2, nowTimestamp);
insertStmt.setTimestamp(3, nowTimestamp);
insertStmt.setTimestamp(4, nowTimestamp);
insertStmt.executeUpdate();
} finally {
try {
insertStmt.close();
} catch (Throwable t) {
// do nothing
}
}
System.out.println("os_name, ts, ts_with_tz, ts_with_local_tz");
// Read back everything in the DB
PreparedStatement selectStmt = conn.prepareStatement(
"SELECT os_name, ts, ts_with_tz, ts_with_local_tz"
+ " FROM dom_fraud_beacon.x_tst_ts_tab");
ResultSet result = null;
try {
result = selectStmt.executeQuery();
while (result.next()) {
System.out.println(
String.format("%s,%s,%s,%s",
result.getString(1),
result.getTimestamp(2).toString(),
result.getTimestamp(3).toString(),
result.getTimestamp(4).toString()
));
}
} finally {
try {
result.close();
} catch (Throwable t) {
// do nothing
} finally {
try {
selectStmt.close();
} catch (Throwable t) {
// do nothing
}
}
}
} finally {
try {
conn.close();
} catch (Throwable t) {
// do nothing
}
}
}
}
Tại sao bạn làm điều đó trong giao diện người dùng khi cơ sở dữ liệu có thể thực hiện điều đó một cách tập trung? – Tim
Tôi đang cố gắng hiểu những gì trình điều khiển JDBC làm. Có vẻ như, trong nhật ký của tôi, nó gửi một chuỗi biểu diễn thời gian cục bộ cho Oracle. Điều này làm phiền tôi. – drinian
[tài liệu này] (http://docs.oracle.com/javase/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame10.html) gợi ý rằng những gì được gửi bởi trình điều khiển JDBC không phải là một chuẩn hóa (tức là UTC) dấu thời gian nhưng một dấu thời gian địa phương múi giờ (những gì tôi sẽ gọi ngẫu nhiên) và máy chủ có nghĩa vụ phải tính toán ngày của nó bằng cách sử dụng múi giờ của máy chủ có trình điều khiển. Điều này phù hợp với phát hiện của bạn. Và có điều này là làm phiền. –