Improved removeOld method in BulkOperationRepository to fix subquery limitations in MySQL and optimize deletion logic.

This commit is contained in:
Jan 2026-01-28 11:21:00 +01:00
parent ffc08ebff6
commit a381ca7ef8

View file

@ -69,14 +69,27 @@ public class BulkOperationRepository {
@Transactional
public void removeOld(Integer userId) {
// First, update sys_error records to set bulk_operation_id to NULL
// for bulk operations that will be deleted (all but the 10 newest for the current user)
// Build subquery to get the 10 newest operations
String newestSubquery = "SELECT id FROM bulk_operation WHERE user_id = ? AND state NOT IN ('SCHEDULED', 'PROCESSING') ORDER BY created_at DESC ";
String newestWithLimit = newestSubquery + dialectProvider.buildPaginationClause(10, 0);
// First, fetch the IDs of the 10 newest operations to keep
// (MySQL doesn't support LIMIT in IN/NOT IN subqueries)
String fetchNewestSql = "SELECT id FROM bulk_operation WHERE user_id = ? AND state NOT IN ('SCHEDULED', 'PROCESSING') ORDER BY created_at DESC " +
dialectProvider.buildPaginationClause(10, 0);
Object[] paginationParams = dialectProvider.getPaginationParameters(10, 0);
Object[] fetchParams = new Object[]{userId, paginationParams[0], paginationParams[1]};
List<Integer> newestIds = jdbcTemplate.queryForList(fetchNewestSql, Integer.class, fetchParams);
// If there are 10 or fewer operations, nothing to delete
if (newestIds.size() <= 10) {
return;
}
// Build comma-separated list of IDs to keep
String idsToKeep = newestIds.stream()
.map(String::valueOf)
.reduce((a, b) -> a + "," + b)
.orElse("0");
// Update sys_error records to set bulk_operation_id to NULL for operations that will be deleted
String updateErrorsSql = String.format("""
UPDATE sys_error
SET bulk_operation_id = NULL
@ -84,29 +97,21 @@ public class BulkOperationRepository {
SELECT id FROM bulk_operation
WHERE user_id = ?
AND state NOT IN ('SCHEDULED', 'PROCESSING')
AND id NOT IN (
%s
AND id NOT IN (%s)
)
)
""", newestWithLimit);
""", idsToKeep);
// Combine params: userId for outer query, userId + pagination params for subquery
Object[] updateParams = new Object[]{userId, userId, paginationParams[0], paginationParams[1]};
jdbcTemplate.update(updateErrorsSql, updateParams);
jdbcTemplate.update(updateErrorsSql, userId);
// Then delete the old bulk_operation entries (keeping only the 10 newest for the current user)
// Delete the old bulk_operation entries (keeping only the 10 newest for the current user)
String deleteBulkSql = String.format("""
DELETE FROM bulk_operation
WHERE user_id = ?
AND state NOT IN ('SCHEDULED', 'PROCESSING')
AND id NOT IN (
%s
)
""", newestWithLimit);
AND id NOT IN (%s)
""", idsToKeep);
// Combine params: userId for WHERE clause, userId + pagination params for subquery
Object[] deleteParams = new Object[]{userId, userId, paginationParams[0], paginationParams[1]};
jdbcTemplate.update(deleteBulkSql, deleteParams);
jdbcTemplate.update(deleteBulkSql, userId);
}
@Transactional