0
votes

I have created a executorservice to call the below listed query with different date ranges. When I run it synchronously I don't see any errors. However when I initiate a number of threads in parallel to invoke getTransactionResult , I see

java.util.concurrent.ExecutionException: org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [Query]; ORA-01841: (full) year must be between -4713 and +9999, and not be 0 ; nested exception is java.sql.SQLDataException: ORA-01841: (full) year must be between -4713 and +9999, and not be 0

at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at com.cloud.cloudreport.CloudReportApplication.lambda$1(CloudReportApplication.java:94) at java.util.ArrayList.forEach(ArrayList.java:1249) at com.cloud.cloudreport.CloudReportApplication.run(CloudReportApplication.java:92) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760) at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) at com.cloud.cloudreport.CloudReportApplication.main(CloudReportApplication.java:43) Caused by: org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL []; ORA-01841: (full) year must be between -4713 and +9999, and not be 0 ; nested exception is java.sql.SQLDataException: ORA-01841: (full) year must be between -4713 and +9999, and not be 0

at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:82) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649) at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:684) at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:711) at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:761) at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:211) at com.cloud.cloudreport.dao.TransactionRespository.getTransactionResult(TransactionRespository.java:68) at com.cloud.cloudreport.dao.TransactionRespository$$FastClassBySpringCGLIB$$60dee75d.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) at com.cloud.cloudreport.dao.TransactionRespository$$EnhancerBySpringCGLIB$$ca18ee4e.getTransactionResult() at com.cloud.cloudreport.CloudReportApplication.lambda$0(CloudReportApplication.java:76) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.sql.SQLDataException: ORA-01841: (full) year must be between -4713 and +9999, and not be 0

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399) at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1017) at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:655) at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:249) at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:566) at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:215) at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:58) at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:776) at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:897) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1034) at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3820) at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3867) at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1502) at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:692) at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633) ... 18 more

Are there any changes that i need to make to this in order to execute the method in parellel?

    @Repository
public class TransactionRespository {
    private static Logger LOG = LoggerFactory.getLogger(TransactionRespository.class);

    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;

    private String transactionQuery = " query goes here";

    public TransactionDetails getTransactionResult(String serviceName, String operationName, Date startDate,
            Date endDate) {

        SqlParameterSource namedParameters = new MapSqlParameterSource("serviceName", serviceName)
                .addValue("operationName", operationName)
                .addValue("startDate", new DateTime(startDate).toString("yyyy-MM-dd HH:mm:ss"))
                .addValue("endDate", new DateTime(endDate).toString("yyyy-MM-dd HH:mm:ss"));

        try{
            return (TransactionDetails) this.jdbcTemplate.queryForObject(transactionQuery, namedParameters,(rs,rowNum)->{
                TransactionDetails transactionDetails = new TransactionDetails();
                TransactionResult result = new TransactionResult();
                transactionDetails.setStartDate(new DateTime(startDate).toString("yyyy-MM-dd HH:mm:ss"));
                transactionDetails.setEndDate(new DateTime(endDate).toString("yyyy-MM-dd HH:mm:ss"));
                result.setSuccessfulTransactions(rs.getInt(2));
                result.setFailedTransactions(rs.getInt(3));
                Map<String,TransactionResult> operationResult = new TreeMap<>();
                operationResult.put(operationName, result);
                transactionDetails.setOperationResult(operationResult);

                return transactionDetails;
            });         
        }  catch (EmptyResultDataAccessException e) {
            LOG.debug("start date :: {} , end date :: {} " , new DateTime(startDate).toString("yyyy-MM-dd HH:mm:ss"), new DateTime(endDate).toString("yyyy-MM-dd HH:mm:ss"));
            return null;
        }


    }
1
When asking about an exception, always post the complete stack trace of the exception.JB Nizet
Sure @JBNizet , I have updated the stacktrace now. The exception that I see doesn't occur when running sequentially and also does not occur during parallel execution on few occasions.Punter Vicky
The exception clearly shows that you're trying pass an invalid date somehow in the parameters: (full) year must be between -4713 and +9999, and not be 0. A first smell is that you're passing dates as strings, instead of using a Date or Timestamp type. Check the data.JB Nizet

1 Answers

1
votes

getTransactionResult(...) has no synchronization whatsoever. The container can manage stuff but it is up to you to keep order. The container has no way to know what needs synchronization.

You can make the method synchronized or follow this

synchronized method or use spring @transactional?