我已经四处寻找,但令人惊讶的是无法为Oracle JDBC找到答案。 This closely related question有PostgreSQL和MySQL的答案。
基本上,如果我在两个不同时区有两个应用服务器将时间戳写入一个Oracle数据库,会发生什么?感谢。
编辑:我应该补充一点,当我进行查询时,JDBC似乎是发送到数据库的值是在我的本地时区。
答案 0 :(得分:9)
我整理了一些测试JDBC代码,以确切了解发生了什么。结果很有趣。 Oracle有三种密切相关的数据类型:TIMESTAMP
,TIMESTAMP WITH TIME ZONE
和TIMESTAMP WITH LOCAL TIME ZONE
。我使用完全相同的代码,并从两个不同的框中运行它,一个在“America / New_York”时区,一个在UTC上运行。两者都以UTC格式运行相同的数据库。我使用的是Oracle 11.2.0.2.0驱动程序。
TIMESTAMP
列设置为执行Java代码的计算机上的本地时间。没有进行时区翻译。TIMESTAMP WITH TIME ZONE
列将时间转换为JDBC客户端所在的任何时区。TIMESTAMP WITH LOCAL TIME ZONE
列还将时间转换为JDBC客户端所在的任何时区。 This article,有点旧,表示如果你想做索引或分区之类的事情,TIMESTAMP WITH TIME ZONE
几乎没用。但是,似乎TIMESTAMP WITH LOCAL TIME ZONE
可能非常有用。 (不确定如果更改服务器的时区会发生什么,但它似乎对JDBC客户端的本地时区是智能的)。我没有机会用这些数据类型测试索引行为等。
如果您想在您的环境中重现我的测试,请在下面的示例课程中粘贴。
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
}
}
}
}