我正在使用java进行Oracle Select for Update,它可以按时运行,有时会挂起会话并且无法删除锁定的会话(必须手动终止会话) 这适用于大多数场景,但是当我将它部署在两个服务器(Web服务)并同时请求它们发生这种情况时,我无法理解它是否是我的代码的问题, 我的代码
public boolean checkJobStatus(long taskId)
{
Connection con = null;
PreparedStatement selectForUpdate = null;
String lastJobStatus = null;
boolean runNow = false;
try
{
con = conPool.getConnection();
con.setAutoCommit(false);
selectForUpdate = con.prepareStatement("SELECT LAST_JOB_STATUS FROM ADM_JOB WHERE TASK_ID = ? FOR UPDATE ");
selectForUpdate.setLong(1, taskId);
ResultSet resultSet = selectForUpdate.executeQuery();
while(resultSet.next())
{
if (resultSet.getObject("LAST_JOB_STATUS") == null)
{
lastJobStatus = ScheduledJob.STATUS_FAILED;
}
else
{
lastJobStatus = resultSet.getString("LAST_JOB_STATUS");
}
}
if(ScheduledJob.STATUS_RUNNING.equalsIgnoreCase(lastJobStatus) || ScheduledJob.STATUS_STARTED.equalsIgnoreCase(lastJobStatus))
{
runNow = false;
// commit n update setting autocommit to true
selectForUpdate = con.prepareStatement("UPDATE ADM_JOB SET LAST_JOB_STATUS =? WHERE TASK_ID = ?");
selectForUpdate.setString(1, lastJobStatus);
selectForUpdate.setLong(2, taskId);
selectForUpdate.executeUpdate();
}
else
{
runNow =true;
// commit n update setting autocommit to true
selectForUpdate = con.prepareStatement("UPDATE ADM_JOB SET LAST_JOB_STATUS =? WHERE TASK_ID = ?");
selectForUpdate.setString(1, ScheduledJob.STATUS_STARTED);
selectForUpdate.setLong(2, taskId);
selectForUpdate.executeUpdate();
con.commit();
con.setAutoCommit(true);
}
} catch (SQLException e)
{
Logger.getLogger( "" ).log(Level.SEVERE, "Error in getting database connection", e);
try
{
con.rollback(); // rolling back the row lock in case of a exception
} catch (SQLException e1)
{
e1.printStackTrace();
}
}
finally
{
DBUtility.close( selectForUpdate );
DBUtility.close( con );
}
return runNow;
}
答案 0 :(得分:1)
提交仅在else分支中发生。如果这种情况没有发生,那么事务就不会被关闭,所以第二个线程会在select for update上永远挂起。