1

so I have a problem and I am kind of new with spring. So basically I want that nothing is commited until the end of "retrieveAndSaveInformationFromBac()". For the moment if an exception is throw some changes will be commited. Here is the code:

public void retrieveAndSaveInformationFromBac() throws ClientWSBacException {
logger.info("Start BATCH BAC");
BatchContextManager.useBatchSchemaForCurrentThread();
Map<ClasseId, Classe> mapClasses = new HashMap<>();
try {
  logger.info("Deleting existant table...");

  deleteAllTables();
  ClientWSBac client = new ClientWSBac(productService);
  List<ModeleBac> listModeleBacToSave = new ArrayList<>();
  for(VehiculeType type : VehiculeType.values()){
    logger.info("Saving the type : "+ type);
    Map<BacFileKey, List<ModeleBac>> mapModeleBac = client.retrieveAndSaveAllFromBac(type, mapClasses);

    listModeleBacToSave = new ArrayList<>();
    for(List<ModeleBac> listModeleBac : mapModeleBac.values()) {
      for(ModeleBac modele : listModeleBac) {


        if(modele.getNivsBac().size() > 0){
          checkEnDescriprions(modele);
          listModeleBacToSave.add(modele);
        }
      }
      if(listModeleBacToSave.size()> 500){
          saveListModeleBac(listModeleBacToSave);
      }

    }
    saveListModeleBac(listModeleBacToSave);
  }
  saveClasseAndTypeCarrosserie(mapClasses);
  logger.info("END OF THE BATCH");
  switchDataSourcesAfterBatch();
} catch (Exception e) {
  logger.error("Error during importation", e);
  throw new ClientWSBacException("Error during importation.Stopping the process....");
}finally{
  BatchContextManager.clear();
}}

And this is where I "save" my info:

@Transactional
private void saveListModeleBac(List<ModeleBac> listModeleBac){
long startTime = System.nanoTime();
  try{
    modeleBacDAO.save(listModeleBac);
  } catch (Exception e){
    e.printStackTrace();
    logger.error("Error during the save of the informations..");
    throw e;
 }
long endTime = System.nanoTime();
long duration = ((endTime - startTime)/1000000000);
logger.debug("Number of insert : " + String.valueOf(listModeleBac.size())+ " in " + String.valueOf(duration) + " seconds" );}

And here is where I delete the table:

@Transactional
 private void deleteAllTables(){
if(databaseMode.equals(DatabaseMode.H2)){
  modeleBacDAO.deleteAllModeleBac();
  classeDAO.deleteAllInBatch();
  typeCarrosserieDAO.deleteAllInBatch();
}else{
  dataSourceUtils.callStoredProcVideTable(currentDBSchemaResolver.resolveCurrentTenantIdentifier());
}}
Leviand
  • 2,745
  • 4
  • 29
  • 43
  • If you add the annotation "@Rollback" to your transaction, which has to be atomic, Either Complete(true) or fail(false), You should be good. Although make sure Each of saveAllTable and Delete table has a specific reason o be atomic. In which case, the db carrier will either execute completely or not at all, nothing in middle like 3 records pushed to db.... – Pavan Kate Jul 26 '18 at 12:49
  • @pavan So if an exception is throw, cause of the annotation "@Rollback", nothing will be commited until "retrieveAndSaveInformationFromBac()" will be finished? Sorry I am not that good in english :) – Isaac Fiset Jul 26 '18 at 12:59
  • It causes the state to be either full with all tables or no insertions at all(if some exception is thrown midway).. If any have been committed, then they are RollBack, like rollback-transaction in Database.This way no stale data is found in DB. – Pavan Kate Jul 26 '18 at 13:08

2 Answers2

2

@Transactional can't work on private method because it's applied using an aspect (using dynamic proxies)

Basically you want the retrieveAndSaveInformationFromBac() to be a single unit of work, ie. a transaction.

So annotate it with @Transactional.

Gab
  • 7,869
  • 4
  • 37
  • 68
0

Since you are using Hibernate , you can handle this by a property:

<property name="hibernate.connection.autocommit">false</property>

Then you can commit with the transaction, like

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//do stuff and then
tx.commit();
Leviand
  • 2,745
  • 4
  • 29
  • 43
  • 1
    In this context do you think it will work if I put this in my main function? Thank you! – Isaac Fiset Jul 26 '18 at 12:55
  • if you mean the property, yes, it will work for any update / insert query you'll do ! Glad to have helped :) – Leviand Jul 26 '18 at 12:58
  • 1
    I will check with my people if I can make a change in the properties. It's a big project so I am not sure if it will be accepted but it's a very good alternative thanks! :) – Isaac Fiset Jul 26 '18 at 13:02
  • transaction are managed here by the container (here spring), so there is no need to (and you shouldn't) manage it manually, use `@Transactional` instead – Gab Jul 26 '18 at 14:00
  • Moreover the `autocommit` property is obviously false by default in hibernate, this answer is simply wrong – Gab Jul 26 '18 at 14:07