【问题标题】:Spring JDBCTemplate - Concurrent CallsSpring JDBCTemplate - 并发调用
【发布时间】:2017-07-29 09:47:52
【问题描述】:

我创建了一个执行器服务来调用下面列出的具有不同日期范围的查询。当我同步运行它时,我看不到任何错误。但是,当我并行启动多个线程以调用 getTransactionResult 时,我看到了

java.util.concurrent.ExecutionException: org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [查询]; ORA-01841: (完整) 年份必须是 介于 -4713 和 +9999 之间,且不为 0 ;嵌套异常是 java.sql.SQLDataException:ORA-01841:(完整)年份必须介于 -4713 和 +9999,且不为 0

在 java.util.concurrent.FutureTask.report(FutureTask.java:122) 在 java.util.concurrent.FutureTask.get(FutureTask.java:192) 在 com.cloud.cloudreport.CloudReportApplication.lambda$1(CloudReportApplication.java:94) 在 java.util.ArrayList.forEach(ArrayList.java:1249) 在 com.cloud.cloudreport.CloudReportApplication.run(CloudReportApplication.java:92) 在 org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) 在 org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760) 在 org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:315) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) 在 com.cloud.cloudreport.CloudReportApplication.main(CloudReportApplication.java:43) 引起:org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL []; ORA-01841:(完整)年份必须 介于 -4713 和 +9999 之间,且不为 0 ;嵌套异常是 java.sql.SQLDataException:ORA-01841:(完整)年份必须介于 -4713 和 +9999,且不为 0

在 org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:82) 在 org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) 在 org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) 在 org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649) 在 org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:684) 在 org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:711) 在 org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:761) 在 org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:211) 在 com.cloud.cloudreport.dao.TransactionRespository.getTransactionResult(TransactionRespository.java:68) 在 com.cloud.cloudreport.dao.TransactionRespository$$FastClassBySpringCGLIB$$60dee75d.invoke() 在 org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 在 org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 在 org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 在 org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) 在 com.cloud.cloudreport.dao.TransactionRespository$$EnhancerBySpringCGLIB$$ca18ee4e.getTransactionResult() 在 com.cloud.cloudreport.CloudReportApplication.lambda$0(CloudReportApplication.java:76) 在 java.util.concurrent.FutureTask.run(FutureTask.java:266) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 在 java.lang.Thread.run(Thread.java:745) 引起: java.sql.SQLDataException:ORA-01841:(完整)年份必须介于 -4713 和 +9999,且不为 0

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

为了并行执行该方法,我需要对此进行任何更改吗?

    @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;
        }


    }

【问题讨论】:

  • 询问异常时,请务必发布异常的完整堆栈跟踪。
  • 当然@JBNizet,我现在已经更新了堆栈跟踪。我看到的异常在顺序运行时不会发生,在少数情况下也不会在并行执行期间发生。
  • 异常清楚地表明您正在尝试以某种方式在参数中传递无效日期:(完整)年份必须介于 -4713 和 +9999 之间,而不是 0 .第一个味道是您将日期作为字符串传递,而不是使用 Date 或 Timestamp 类型。检查数据。

标签: java spring jdbctemplate


【解决方案1】:

getTransactionResult(...) 没有任何同步。容器可以管理东西,但保持秩序取决于您。容器无法知道什么需要同步。

您可以使方法同步或遵循此

synchronized method or use spring @transactional?

【讨论】:

  • 我尝试使用这两个选项,但交易正在按顺序处理。但是我希望它们并行运行。
  • 我会在里面放一个断点。运行线程,看看你有多少命中。从那里去
  • 当然@efekctive。我会试试的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 1970-01-01
  • 2013-07-25
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
相关资源
最近更新 更多