簡體   English   中英

來自Java Calendar操作的結果不一致

[英]Inconsistent results from java Calendar manipulation

我有一個cron工作來清除超過某個月數(由用戶設置)的數據。 cron作業調用purgeData()方法,該方法從postgres表中清除數據。 我從當前日期(通過GregorianCalendar.getInstance )操作java Calendar來確定在之前刪除數據的目標日期。

我的問題是日歷操作和/或將新操作的日歷轉換為字符串以便在postgres中使用偶爾會失敗,將目標日期設置為刪除當前日期之前的所有內容的當前日期,而不是早於1的數據(或#數月保持數月)。

這是我簡單的日期格式:

public static final SimpleDateFormat dateFormatter = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss.SSS");

這是我的方法:

public String purgeData() throws ParseException {
    Connection con = null;
    String sqlString = "";
    PreparedStatement pst = null;
    String returnString = "";

    Calendar startDate = GregorianCalendar.getInstance();
    returnString += "# Months to keep data: " + getNumMonthsKeepData();
    startDate.add(Calendar.MONTH, getNumMonthsKeepData() * -1);
    String targetDate = dateFormatter.format(startDate.getTime());
    Calendar today = GregorianCalendar.getInstance();

    returnString +=" Target date (string): " + targetDate + " start date (Calendar): " + startDate.toString() + ", Start month: " + startDate.get(Calendar.MONTH) + ", Current month: " + today.get(Calendar.MONTH);

    if (startDate.get(Calendar.MONTH)!= today.get(Calendar.MONTH)) {

        String tableName = getPreviousMonthlyTable();
        try {
            con = getDBConnection();

            try {
                // Delete old data
                sqlString = "DELETE FROM \"" + tableName
                        + "\" WHERE  datetime < '" + targetDate + "'";

                pst = con.prepareStatement(sqlString);
                int rowsDeleted = pst.executeUpdate();
                returnString += "SUCCESS: Purged data prior to " + targetDate
                        + " # rows deleted: " + rowsDeleted
                        + "( # rows deleted last purge: "
                        + numRowsDeletedPreviously + " )\n";

            } catch (SQLException ex) {
                returnString += "FAILED to execute: " + sqlString;
            }

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                return null;
            }
        } catch (SQLException ex) {
            returnString += "Delete from table fail: " + ex.getMessage();
        }
    } else {
        returnString += "FAIL:  Fail to delete data prior to: " + targetDate + ". Start month: " + startDate.get(Calendar.MONTH)
                + " equals current month: " + today.get(Calendar.MONTH);
    }
    return returnString;
}

日期失敗似乎是隨機的,因為在一次部署成功時,它會在另一次部署失敗。

失敗輸出:

20150421-00:33:11.006 Postgres通知 - 清除:#保存數據的月份:1目標日期(字符串): 2015-04-21 00:00:00.001 ,開始月份:2,當前月份:3成功:先前清除數據至2015-04-21 00:00:00.001#rows deleted:7575704(#rows deleted last purge:26608)

注意:目標日期應為2015-03-21 00:00:30.000(請注意,由於cron作業從00:30開始每4小時運行一次,因此也是30分鍾)

較舊的故障輸出(在添加更多日志之前): 20150414-20:37:53.347 Postgres通知 - 清除:成功: 2015-04-14之前的清除數據19:00:00.004 #rows deleted:12195291(#rows刪除最后凈化:128570)

注意:之前的清除數據應該是2015-03-14 20:30:00.000(請注意,由於cron作業從00:30開始每4小時運行一次,因此也是1小時30分鍾)

成功輸出: 20150421-00:30:02.559 Postgres通知 - 清除:#個月保存數據:1目標日期(字符串):2015-03-21 00:30:00.003,開始月份:2,當前月份:3成功: 2015-03-21 00:30:00.003之前的清除數據#rows刪除:139757(#rows刪除最后清除:33344)

似乎日期操作實際上有效,如開始月份和當前月份的輸出所示。 在兩種故障情況下,整數值都不同。 但是,將字符串轉換為SimpleDateFormat似乎是錯誤的。

我已經閱讀了javadocs,因為在Calendar上設置字段時,必須調用get()來重新計算時間。 但是,add()應該強制重新計算。

你的dateformatter不是線程安全的,將它存儲在一個類變量中,讓多個線程同時敲擊它會給你帶來無效的結果。

這在SimpleDateFormatAPI文檔中記錄,標題為Synchronization:

日期格式未同步。 建議為每個線程創建單獨的格式實例。 如果多個線程同時訪問格式,則必須在外部進行同步。

一個解決方法是讓您的方法創建自己的SimpleDateFormatter實例。 還有更多選項,在相關問題中列出: 制作DateFormat Threadsafe。 使用什么,同步或線程本地

但是,不需要格式化日期,而是可以將日期作為參數傳遞給PreparedStatement:

sqlString = "DELETE FROM \"" + tableName + "\" WHERE datetime < ?";
pst = con.prepareStatement(sqlString);
pst.setTimestamp(1, new Timestamp(startDate.getTime()));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM