diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java index 2c2b19484..30ceb9598 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java @@ -38,12 +38,14 @@ public class JobExecution extends Entity { private volatile BatchStatus status = BatchStatus.STARTING; - private volatile Date startTime = new Date(System.currentTimeMillis()); + private volatile Date startTime = null; + + private volatile Date createTime = new Date(System.currentTimeMillis()); private volatile Date endTime = null; private volatile ExitStatus exitStatus = ExitStatus.UNKNOWN; - + private ExecutionContext executionContext = new ExecutionContext(); /** @@ -199,4 +201,18 @@ public class JobExecution extends Entity { public ExecutionContext getExecutionContext() { return executionContext; } + + /** + * @return the time when this execution was created. + */ + public Date getCreateTime() { + return createTime; + } + + /** + * @param createTime creation time of this execution. + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java index 1242e224e..edd639abd 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java @@ -42,25 +42,25 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements + "where JOB_INSTANCE_ID = ?"; private static final String SAVE_JOB_EXECUTION = "INSERT into %PREFIX%JOB_EXECUTION(JOB_EXECUTION_ID, JOB_INSTANCE_ID, START_TIME, " - + "END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, VERSION) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + "END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String CHECK_JOB_EXECUTION_EXISTS = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?"; private static final String UPDATE_JOB_EXECUTION = "UPDATE %PREFIX%JOB_EXECUTION set START_TIME = ?, END_TIME = ?, " - + " STATUS = ?, CONTINUABLE = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ? where JOB_EXECUTION_ID = ?"; + + " STATUS = ?, CONTINUABLE = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ? where JOB_EXECUTION_ID = ?"; - private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE from %PREFIX%JOB_EXECUTION" + private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION" + " where JOB_INSTANCE_ID = ?"; - private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE from %PREFIX%JOB_EXECUTION" - + " where JOB_INSTANCE_ID = ? and START_TIME = (SELECT max(START_TIME) from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ?)"; + private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION" + + " where JOB_INSTANCE_ID = ? and CREATE_TIME = (SELECT max(CREATE_TIME) from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ?)"; private int exitMessageLength = DEFAULT_EXIT_MESSAGE_LENGTH; private DataFieldMaxValueIncrementer jobExecutionIncrementer; - + private LobHandler lobHandler = new DefaultLobHandler(); - + private JdbcExecutionContextDao ecDao = new JdbcExecutionContextDao(); /** @@ -114,12 +114,13 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements Object[] parameters = new Object[] { jobExecution.getId(), jobExecution.getJobId(), jobExecution.getStartTime(), jobExecution.getEndTime(), jobExecution.getStatus().toString(), jobExecution.getExitStatus().isContinuable() ? "Y" : "N", jobExecution.getExitStatus().getExitCode(), - jobExecution.getExitStatus().getExitDescription(), jobExecution.getVersion() }; + jobExecution.getExitStatus().getExitDescription(), jobExecution.getVersion(), + jobExecution.getCreateTime() }; getJdbcTemplate().update( getQuery(SAVE_JOB_EXECUTION), parameters, new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.CHAR, - Types.VARCHAR, Types.VARCHAR, Types.INTEGER }); + Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP }); } /** @@ -134,6 +135,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements Assert.notNull(jobExecution); Assert.notNull(jobExecution.getJobId(), "JobExecution Job-Id cannot be null."); Assert.notNull(jobExecution.getStatus(), "JobExecution status cannot be null."); + Assert.notNull(jobExecution.getCreateTime(), "JobExecution create time cannot be null"); } /** @@ -158,7 +160,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements Object[] parameters = new Object[] { jobExecution.getStartTime(), jobExecution.getEndTime(), jobExecution.getStatus().toString(), jobExecution.getExitStatus().isContinuable() ? "Y" : "N", jobExecution.getExitStatus().getExitCode(), exitDescription, jobExecution.getVersion(), - jobExecution.getId() }; + jobExecution.getCreateTime(), jobExecution.getId() }; if (jobExecution.getId() == null) { throw new IllegalArgumentException("JobExecution ID cannot be null. JobExecution must be saved " @@ -176,7 +178,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements getQuery(UPDATE_JOB_EXECUTION), parameters, new int[] { Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.CHAR, Types.VARCHAR, Types.VARCHAR, - Types.INTEGER, Types.INTEGER }); + Types.INTEGER, Types.TIMESTAMP, Types.INTEGER }); } /** @@ -219,6 +221,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements jobExecution.setEndTime(rs.getTimestamp(3)); jobExecution.setStatus(BatchStatus.getStatus(rs.getString(4))); jobExecution.setExitStatus(new ExitStatus("Y".equals(rs.getString(5)), rs.getString(6), rs.getString(7))); + jobExecution.setCreateTime(rs.getDate(8)); jobExecution.setExecutionContext(findExecutionContext(jobExecution)); return jobExecution; } @@ -247,7 +250,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements } public void saveOrUpdateExecutionContext(JobExecution jobExecution) { - ecDao.saveOrUpdateExecutionContext(jobExecution); + ecDao.saveOrUpdateExecutionContext(jobExecution); } public void setLobHandler(LobHandler lobHandler) { diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java index 1574b94e7..cec55a025 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java @@ -16,9 +16,9 @@ import org.springframework.util.Assert; * */ public class MapJobExecutionDao implements JobExecutionDao { - + private static Map executionsById = TransactionAwareProxyFactory.createTransactionalMap(); - + private static Map contextsByJobExecutionId = TransactionAwareProxyFactory.createTransactionalMap(); private static long currentId = 0; @@ -76,7 +76,7 @@ public class MapJobExecutionDao implements JobExecutionDao { if (lastExec == null) { lastExec = exec; } - if (lastExec.getStartTime().getTime() < exec.getStartTime().getTime()) { + if (lastExec.getCreateTime().before(exec.getCreateTime())) { lastExec = exec; } } @@ -89,6 +89,6 @@ public class MapJobExecutionDao implements JobExecutionDao { public void saveOrUpdateExecutionContext(JobExecution jobExecution) { contextsByJobExecutionId.put(jobExecution.getId(), jobExecution.getExecutionContext()); - + } } diff --git a/spring-batch-core/src/main/resources/schema-db2.sql b/spring-batch-core/src/main/resources/schema-db2.sql index 8e10608be..8e2378d72 100644 --- a/spring-batch-core/src/main/resources/schema-db2.sql +++ b/spring-batch-core/src/main/resources/schema-db2.sql @@ -21,7 +21,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID BIGINT PRIMARY KEY , VERSION BIGINT, JOB_INSTANCE_ID BIGINT NOT NULL, - START_TIME TIMESTAMP NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL, END_TIME TIMESTAMP DEFAULT NULL, STATUS VARCHAR(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/main/resources/schema-derby.sql b/spring-batch-core/src/main/resources/schema-derby.sql index 410d4b45c..d7ca77d72 100644 --- a/spring-batch-core/src/main/resources/schema-derby.sql +++ b/spring-batch-core/src/main/resources/schema-derby.sql @@ -21,7 +21,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, VERSION BIGINT, JOB_INSTANCE_ID BIGINT NOT NULL, - START_TIME TIMESTAMP NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL, END_TIME TIMESTAMP DEFAULT NULL, STATUS VARCHAR(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/main/resources/schema-hsqldb.sql b/spring-batch-core/src/main/resources/schema-hsqldb.sql index af35b797e..3183770b4 100644 --- a/spring-batch-core/src/main/resources/schema-hsqldb.sql +++ b/spring-batch-core/src/main/resources/schema-hsqldb.sql @@ -21,7 +21,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID BIGINT IDENTITY PRIMARY KEY , VERSION BIGINT, JOB_INSTANCE_ID BIGINT NOT NULL, - START_TIME TIMESTAMP NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL, END_TIME TIMESTAMP DEFAULT NULL, STATUS VARCHAR(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/main/resources/schema-mysql.sql b/spring-batch-core/src/main/resources/schema-mysql.sql index ffd7d4e5c..00dd797c4 100644 --- a/spring-batch-core/src/main/resources/schema-mysql.sql +++ b/spring-batch-core/src/main/resources/schema-mysql.sql @@ -21,7 +21,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID BIGINT PRIMARY KEY , VERSION BIGINT, JOB_INSTANCE_ID BIGINT NOT NULL, - START_TIME DATETIME NOT NULL, + CREATE_TIME DATETIME NOT NULL, + START_TIME DATETIME DEFAULT NULL, END_TIME DATETIME DEFAULT NULL, STATUS VARCHAR(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/main/resources/schema-oracle10g.sql b/spring-batch-core/src/main/resources/schema-oracle10g.sql index bbf3dc65d..cee2edb6a 100644 --- a/spring-batch-core/src/main/resources/schema-oracle10g.sql +++ b/spring-batch-core/src/main/resources/schema-oracle10g.sql @@ -21,7 +21,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID NUMBER(38) PRIMARY KEY , VERSION NUMBER(38), JOB_INSTANCE_ID NUMBER(38) NOT NULL, - START_TIME TIMESTAMP NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL, END_TIME TIMESTAMP DEFAULT NULL, STATUS VARCHAR2(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/main/resources/schema-postgresql.sql b/spring-batch-core/src/main/resources/schema-postgresql.sql index 8d658bb50..4eb94b2e4 100644 --- a/spring-batch-core/src/main/resources/schema-postgresql.sql +++ b/spring-batch-core/src/main/resources/schema-postgresql.sql @@ -21,7 +21,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID BIGINT PRIMARY KEY , VERSION BIGINT, JOB_INSTANCE_ID BIGINT NOT NULL, - START_TIME TIMESTAMP NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL, END_TIME TIMESTAMP DEFAULT NULL, STATUS VARCHAR(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/main/sql/init.sql.vpp b/spring-batch-core/src/main/sql/init.sql.vpp index 7ba1a3965..9ed60a596 100644 --- a/spring-batch-core/src/main/sql/init.sql.vpp +++ b/spring-batch-core/src/main/sql/init.sql.vpp @@ -10,7 +10,8 @@ CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID ${BIGINT} $!{IDENTITY} PRIMARY KEY $!{GENERATED}, VERSION ${BIGINT}, JOB_INSTANCE_ID ${BIGINT} NOT NULL, - START_TIME ${TIMESTAMP} NOT NULL, + CREATE_TIME ${TIMESTAMP} NOT NULL, + START_TIME ${TIMESTAMP} DEFAULT NULL, END_TIME ${TIMESTAMP} DEFAULT NULL, STATUS ${VARCHAR}(10), CONTINUABLE CHAR(1), diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobDaoTests.java index 45b736d27..7eb23bfbb 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobDaoTests.java @@ -260,7 +260,7 @@ public abstract class AbstractJobDaoTests extends AbstractTransactionalDataSourc lastExecution.setStatus(BatchStatus.STARTED); int JUMP_INTO_FUTURE = 1000; // makes sure start time is 'greatest' - lastExecution.setStartTime(new Date(System.currentTimeMillis() + JUMP_INTO_FUTURE)); + lastExecution.setCreateTime(new Date(System.currentTimeMillis() + JUMP_INTO_FUTURE)); jobExecutionDao.saveJobExecution(lastExecution); assertEquals(lastExecution, jobExecutionDao.getLastJobExecution(jobInstance)); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobExecutionDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobExecutionDaoTests.java index f66c9744d..c5e6915ea 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobExecutionDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractJobExecutionDaoTests.java @@ -89,7 +89,7 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional */ public void testGetLastExecution() { JobExecution exec1 = new JobExecution(jobInstance); - exec1.setStartTime(new Date(0)); + exec1.setCreateTime(new Date(0)); ExecutionContext ctx = new ExecutionContext() { { @@ -98,7 +98,7 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional }; JobExecution exec2 = new JobExecution(jobInstance); exec2.setExecutionContext(ctx); - exec2.setStartTime(new Date(1)); + exec2.setCreateTime(new Date(1)); dao.saveJobExecution(exec1); dao.saveJobExecution(exec2);