编写执行时间超过5分钟的方法的最佳方法是什么?

时间:2018-09-29 06:21:22

标签: spring-boot spring-data-jpa

我有一个Java方法,每个午夜执行一次。该方法执行从一个表1到另一表2的备份数据并清除表1。每天table1包含13214215行。

这是我的计划程序方法

    @Scheduled(cron = "0 59 23 * * *")
    public void doAutoBackupProcess() {

        try {
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
            headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");

            HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

            String url = "http://192.168.31.5:8082/scheduler/attendance/backup/call";

            restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
            logger.info("Data Backup success");
        } catch (Exception ex) {
            Logger.getLogger(SchedulerService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

http://192.168.31.5:8082/scheduler/attendance/backup/call 包含以下方法

    @Transactional
    public void doStdAttendanceBackup() {

        List<StudentAttendanceDetails> sads = studentAttendanceDetailsRepository.findAll();     
        studentAttendanceDetailsBackUpRepository.save(copyStudentAttendanceDetailsToStdAttendanceDetailsBackUp(sads));      
        studentAttendanceDetailsRepository.delete(sads);
    }



public List<StdAttendanceDetailsBackUp> copyStudentAttendanceDetailsToStdAttendanceDetailsBackUp(List<StudentAttendanceDetails> sads) {

        List<StdAttendanceDetailsBackUp> sadbus = sads.stream().map((sad) -> {
            StdAttendanceDetailsBackUp sadbu = new StdAttendanceDetailsBackUp();
            BeanUtils.copyProperties(sad, sadbu);
            return sadbu;
        }).collect(Collectors.toList());
        return sadbus;
    }

执行上述方法时,我将面对

  

java.lang.outofmemoryerror gc超出开销限制

  

java.lang.OutOfMemoryError:Java堆空间

例外。我在jvm 2256m中增加了Java堆内存 但是问题没有解决

有人能给我最好的解决方案吗? 谢谢

2 个答案:

答案 0 :(得分:2)

一次备份所有数据的解决方案无法扩展。因此,您应该分页阅读(和删除)更多次。

boolean migratedElements = false;

//if you delete your data, you can page every time first 1000 records or 10000... this can be tuned
Pageable pageable = new PageRequest(0, 1000);

while(!migratedElements) {

    List<StudentAttendanceDetails> sads1000 = studentAttendanceDetailsRepository.findAll(pageable);  

    if(sads1000.size() == 0) {
        migratedElements = true;
    } else {
        studentAttendanceDetailsBackUpRepository.save(copyStudentAttendanceDetailsToStdAttendanceDetailsBackUp(sads));      
        studentAttendanceDetailsRepository.delete(sads);
    }  

}

您还需要为每个页面调用备份休息服务,否则您仍然会遇到内存不足的情况

答案 1 :(得分:0)

实现的方法太多了,F.Y.I。

  1. JDBC提取流

这里是一个例子:

@Autowired
private JdbcTemplate jdbcTemplate;

public void doStdAttendanceBackup() {

    String sql = "select * from *** where c=:c1 and b=:b1";
    jdbcTemplate.setFetchSize(1000); 
    NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);

    Map<String, Object> params = new HashMap<>(2);
    params.put("c1", ***);
    params.put("b1", ***);

    namedParameterJdbcTemplate.query(sql, params, (ResultSet rs) -> {
        // 0. copy rs to StdAttendanceDetailsBackUp;

        // 1. save StdAttendanceDetailsBackUp;

        // 2  delete StudentAttendanceDetails;

        // note: makesure the codes is transactional above
    });
}
  1. 插入Select

请参考:https://www.w3schools.com/sql/sql_insert_into_select.asp

如果两个表都属于一个数据库用户,我认为第二种方法对您更好。