0

I am not able to open new transaction for each item when iterating list using Spring Boot. I want to roll back only the item that is failed and continue with rest of the items in list. There are multiple commits in one transaction and all of them must be rolled back if any failure. My Service code below.

@Service("intentExportImportService")
public class IntentExportImportServiceImpl implements IntentExportImportService {
@Resource(name = "intentExportImportService")
private IntentExportImportService intentExportImportService;

 public  Map<String, Integer> importIntents(ExportImportData exportImportData,boolean overwrite) throws DataAccessLayerException {

    Map<String, Integer> statiscisMap= createOrUpdateIntent(exportImportData,overwrite);
    return statiscisMap;
}

private Map<String, Integer> createOrUpdateIntent(ExportImportData exportImportData,boolean overwrite)throws DataAccessLayerException {
    List<Intent> intentsList = exportImportData.getIntents();
    Map<String,Entity> entityMap = getEntityMap(exportImportData.getEntityList());
    Map<String,Api> apiMap = getApiMap(exportImportData.getApiList());
    Map<String,Integer> statisticsMap = new HashMap<>();
    Long domainId = ExcelUtil.getDomainId(exportImportData.getDomainName());
    for(Intent intent : intentsList) {
        Intent existingIntent =  intentExists(intent.getIntentNm());
       if(existingIntent != null){
           startUpdateIntent(intent,existingIntent,entityMap,apiMap,overwrite,statisticsMap,domainId);
       }else{
           startCreateIntent(intent,entityMap,apiMap,overwrite,statisticsMap,domainId);
       }
    }
    return statisticsMap;
}

@Transactional
public void startUpdateIntent(Intent intent, Intent existingIntent, Map<String, Entity> entityMap, Map<String, Api> apiMap, boolean overwrite, Map<String, Integer> statisticsMap, Long domainId) {

    try {
        intentExportImportService.updateIntent(intent, existingIntent, entityMap, apiMap, overwrite, statisticsMap,domainId);
    }catch (Exception e)
    {
        updateStatisticsMap(FAILED,statisticsMap);
        LOGGER.error("Error Importing Intents to update and hence rolling back intent: "+intent.getIntentNm());

    }
}

@Transactional(value = "dataTxManager", propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, rollbackFor = {
    DuplicateException.class, DataAccessException.class,DataAccessLayerException.class, SQLTimeoutException.class, SQLException.class,Exception.class})
public void updateIntent(Intent intent, Intent existingIntent, Map<String, Entity> entityMap, Map<String, Api> apiMap, boolean overwrite, Map<String, Integer> statisticsMap,Long domainId) throws DataAccessLayerException {

    if(!overwrite){
        LOGGER.info("Not overwriting the Intent: "+intent.getIntentNm()+" as it already exist and overwrite is false");
        throw new DataAccessLayerException(CommonConstants.IMPORT_FAILURE_ERROR_CODE,"rolling back intent importing: "+intent.getIntentNm());
    }
    manageEntitiesAndApis(intent, entityMap, apiMap, overwrite,domainId);
    Long intentId = updateImportedIntent(intent,existingIntent);
    if(intentId != null) {
        updateStatisticsMap(UPDATED, statisticsMap);
    }
}

}

  • See discussion here on self method invocations. https://stackoverflow.com/q/3423972/1356423 Try ,moving `updateIntent(...)` to a separate class or implement one of the other solutions given. – Alan Hay Apr 28 '18 at 09:35

2 Answers2

0

UpdateIntent is already in another class: IntentImportExportService which is injected in the caller as a Resource, so the problem is not there... Are you sure the selected transaction manager supports nested transaction?

p3consulting
  • 2,721
  • 2
  • 12
  • 10
0

I solved the issue by adding try catch inside for loop like below

 @Transactional
public Map<String, Integer> createOrUpdateIntent(ExportImportData exportImportData,boolean overwrite) {
    List<Intent> intentsList = exportImportData.getIntents();
    Map<String,Entity> entityMap = getEntityMap(exportImportData.getEntityList());
    Map<String,Api> apiMap = getApiMap(exportImportData.getApiList());
    Map<String,Integer> statisticsMap = new HashMap<>();
    Long domainId = ExcelUtil.getDomainId(exportImportData.getDomainName());
    for(Intent intent : intentsList) {
        try {
            Intent existingIntent = intentExists(intent.getIntentNm());
            if (existingIntent != null) {
                intentExportImportService.updateIntent(intent, existingIntent, entityMap, apiMap, overwrite, statisticsMap, domainId);
            } else {
                intentExportImportService.createIntent(intent, entityMap, apiMap, overwrite, statisticsMap, domainId);
            }
        } catch (DataAccessLayerException e) {
            updateStatisticsMap(FAILED,statisticsMap);
            LOGGER.error("Error Importing Intents to update and hence rolling back intent: "+intent.getIntentNm());
        }
    }
    return statisticsMap;
}