У нас есть от 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();
}
Через несколько секунд Приложение 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;
}
примерно в 1 из 5или около того выполнения, я вижу текущее время на раньше , чем время создания записи (время входа в систему).Когда это происходит, я вижу вывод оператора отладки, подобный следующему:
db:1538793249000 now:1538793023000 diffSecs:-226
db:1538793249000 now:1538793023000 diffSecs:-202
db:1538793249000 now:1538793023000 diffSecs:-225
Похоже, примерно на 200+ секунд раньше
Если вы заметили одну вещь, тип данных столбца (LOGIN_TIME) является меткой времени, и я использую SYSDATE для ее заполнения.Тем не менее, я также использую SYSDATE, чтобы получить время от ДВОЙНОГО.Из 4-х сред, которые мы имеем, это происходит в одной и не всегда.Что-то не так в коде или возможно, что супер-кластер базы данных Oracle) на самом деле возвращает неправильную дату.