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 @Transactional
public void removeOld(Integer userId) { public void removeOld(Integer userId) {
// First, update sys_error records to set bulk_operation_id to NULL // First, fetch the IDs of the 10 newest operations to keep
// for bulk operations that will be deleted (all but the 10 newest for the current user) // (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 " +
// Build subquery to get the 10 newest operations dialectProvider.buildPaginationClause(10, 0);
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);
Object[] paginationParams = dialectProvider.getPaginationParameters(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(""" String updateErrorsSql = String.format("""
UPDATE sys_error UPDATE sys_error
SET bulk_operation_id = NULL SET bulk_operation_id = NULL
@ -84,29 +97,21 @@ public class BulkOperationRepository {
SELECT id FROM bulk_operation SELECT id FROM bulk_operation
WHERE user_id = ? WHERE user_id = ?
AND state NOT IN ('SCHEDULED', 'PROCESSING') AND state NOT IN ('SCHEDULED', 'PROCESSING')
AND id NOT IN ( AND id NOT IN (%s)
%s
) )
) """, idsToKeep);
""", newestWithLimit);
// Combine params: userId for outer query, userId + pagination params for subquery jdbcTemplate.update(updateErrorsSql, userId);
Object[] updateParams = new Object[]{userId, userId, paginationParams[0], paginationParams[1]};
jdbcTemplate.update(updateErrorsSql, updateParams);
// 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(""" String deleteBulkSql = String.format("""
DELETE FROM bulk_operation DELETE FROM bulk_operation
WHERE user_id = ? WHERE user_id = ?
AND state NOT IN ('SCHEDULED', 'PROCESSING') AND state NOT IN ('SCHEDULED', 'PROCESSING')
AND id NOT IN ( AND id NOT IN (%s)
%s """, idsToKeep);
)
""", newestWithLimit);
// Combine params: userId for WHERE clause, userId + pagination params for subquery jdbcTemplate.update(deleteBulkSql, userId);
Object[] deleteParams = new Object[]{userId, userId, paginationParams[0], paginationParams[1]};
jdbcTemplate.update(deleteBulkSql, deleteParams);
} }
@Transactional @Transactional