Spring Data JPA批处理中的CannotCreateTransactionException

时间:2019-02-28 04:54:23

标签: java mysql spring multithreading hibernate

我正在尝试处理大约1千万条MySQL DB1的记录,然后将它们保存到MySQL DB2

我使用大约50个线程来实现这一目标。生产者从中获取500条记录 MySQL DB1一次,然后将它们放入队列。大约有50位消费者将对其进行处理,然后将其插入MySQL DB2

在大多数情况下,它可以正常工作。但是对于大约5万条记录,它失败了。

分析日志后,我发现抛出了CannotCreateTransactionException

org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.TransactionException: JDBC begin transaction failed:
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:450) ~[spring-orm-5.0.9.RELEASE.jar!/:5.0.9.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:378) ~[spring-tx-5.0.9.RELEASE.jar!/:5.0.9.RELEASE]

此网站上有一些类似的问题,我已经尝试了其中的一些问题:

    MyRepository.saveAll()引发异常后,
  1. 重试5次

  2. BasicDataSource与较大的maxActivesetValidationQuerysetTestOnBorrow一起使用:

    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setMaxActive(100);
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("***");
    dataSource.setUsername("***");
    dataSource.setPassword("***");
    dataSource.setTestOnBorrow(true);
    dataSource.setValidationQuery("SELECT 1");
    dataSource.setMaxActive(30);
    

它仍然不起作用。我该如何解决?

1 个答案:

答案 0 :(得分:0)

我进行了很多搜索并尝试了不同的解决方案。

最后,将配置更改为此后,该异常不再显示:

@Bean
public DataSource poiDataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setMaxActive(100);
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("**");
    dataSource.setUsername("**");
    dataSource.setPassword("**");
    dataSource.setTestOnBorrow(true);
    dataSource.setValidationQuery("SELECT 1");
    dataSource.setMaxActive(30);
    dataSource.setRemoveAbandoned(true);
    dataSource.setMaxWait(60000);
    dataSource.setTimeBetweenEvictionRunsMillis(300000);
    dataSource.setMinEvictableIdleTimeMillis(300000);
    dataSource.setTestWhileIdle(true);
    dataSource.setLogAbandoned(true);
    return dataSource;
}