【问题标题】:SYSDATE in JDBC statements seems to return different times when queried against the same Oracle database对同一个 Oracle 数据库进行查询时,JDBC 语句中的 SYSDATE 似乎返回不同的时间
【发布时间】:2019-03-11 21:17:54
【问题描述】:

我们有 3 到 4 个设置相同的环境,每个环境都有多个集群应用服务器 (WebSphere) 和 Oracle Supercluster 数据库。

我看到的问题似乎仅发生在其中一种环境中,发生率大约为 20%

我们有

  • 两个应用部署到同一个应用服务器集群

  • 两个应用程序使用相同的数据源,配置为使用 Oracle 数据库,即 Oracle 超级集群。

以下是相关表格的结构

TABLE SESSION_TBL 
(
    ID NUMBER(12, 0) NOT NULL, 
    USER_ID VARCHAR2(256 BYTE) NOT NULL, 
    SESSION_ID VARCHAR2(60 BYTE) NOT NULL, 
    LOGIN_TIME TIMESTAMP(6) NOT NULL 
 ) 

应用程序 1 使用 JDBC 存储记录

    String sql = "Insert into SESSION_TBL " +
                 "  (USER_ID, SESSION_ID, LOGIN_TIME ) " +
                 "  values (?,?,SYSDATE)";

    try
    {
        sessionId = getNewSessionId(userId);
        st = conn.prepareStatement(sql);
        st.setString(1, userId);
        st.setString(2, sessionId);
        int rows = st.executeUpdate();
    }

几秒钟后,Application 2 执行以下代码查找第一个应用程序插入的记录并与当前时间进行比较

Statement st = null;
ResultSet result = null;

String sql = " Select * " +
" from SESSION_TBL " +
" where USER_ID = '" + userId + "' " +
" and SESSION_ID = '" + sessionId + "' ";

try {
    st = conn.createStatement();
    result = st.executeQuery(sql);

    if(!result.next()) { // We have no data, need to expire the session
        logger.debug("End hasSessionExpired()");
        return true;
    }
    else {
         logger.debug("SessionInfo:ResultSet not null");
    }


    // Get the time user logged in
    // java.sql.Timestamp
    Timestamp database_date = result.getTimestamp("LOGIN_TIME"); // get date from db
    long databaseDate = database_date.getTime(); // Convert to UNIX time

    // Get the current time from the database, so we are getting the time
    // from the same sources to compare
    // See the code below for this function
    long currentTime = getCurrentTimeFromDB (conn);

    // Both time values would be in milli seconds
    long diffSecs = (currentTime - databaseDate)/1000; 
    logger.info ("db:" + databaseDate + "   now:" + currentTime + " diffSecs:" + diffSecs);

从数据库中获取当前时间的代码

public static long getCurrentTimeFromDB () {
   .
   .
    // Using SYSDATE.  We only need precision upto seconds
    String s = "SELECT SYSDATE NOW FROM DUAL";
    rs = statement.executeQuery(s);
    if (rs.next()) {
        Timestamp dbTime = rs.getTimestamp("NOW");
        currentTime = dbTime.getTime();
    }
    return currentTime;
}

在大约 5 次左右的执行中,我发现当前时间比创建记录的时间(登录时间)。发生这种情况时,我会看到如下调试语句的输出:

db:1538793249000   now:1538793023000 diffSecs:-226
db:1538793249000   now:1538793023000 diffSecs:-202
db:1538793249000   now:1538793023000 diffSecs:-225

似乎早了 200 多秒

如果您注意到一件事,列 (LOGIN_TIME) 的数据类型是时间戳,我正在使用 SYSDATE 来填充它。但是,我也使用 SYSDATE 从 DUAL 获取时间。在我们拥有的 4 个环境中,这发生在一个环境中,但并不总是如此。代码有问题还是数据库Oracle超级集群)实际上返回的日期不正确。

【问题讨论】:

  • 确保您的所有 Oracle 系统都在运行 ntpd 并设置为良好的时间服务器。有关更多说明,请参阅ntppool
  • @ElliottFrisch - 你看到 java 代码有什么问题吗?
  • 是的,它很容易被sql注入;但这与你的时钟无关。
  • @ElliottFrisch - 谢谢!代码是内部的,不会暴露在任何地方。

标签: java oracle jdbc oracle11g websphere


【解决方案1】:

我想我会给出一个答案,以防其他人遇到类似问题。正如人们(在 cmets 中)建议的那样,集群节点时间可能不同步。我们在集群中有 2 个节点,其中一个节点(比当前时间)提前了几分钟。可以通过对每个节点运行 SYSDATE 查询来检测时间是否不同步。

【讨论】:

    猜你喜欢
    • 2019-05-23
    • 1970-01-01
    • 2019-03-03
    • 2020-03-03
    • 2020-01-17
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多