我有一个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堆内存 但是问题没有解决
有人能给我最好的解决方案吗? 谢谢
答案 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。
这里是一个例子:
@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
});
}
请参考:https://www.w3schools.com/sql/sql_insert_into_select.asp
如果两个表都属于一个数据库用户,我认为第二种方法对您更好。