0

I am using TaskExecutor class of Springs to perform asynchronous deletion of a few entries in a database.So basically the execute method of the underlying class is run as a thread to perform asynchronous delete.

In this method I call bean methods that perform deletion of database entries. I have use default Transaction attribute that is PROPAGATION.REQUIRED in the bean methods.underlying is the execute method i am talking about.Basically I need to rollback the entire database transaction once any exception occurs after callig bean methods or if someone cancels the deletion task.

 package com.ibm.security.modeling.async.tasks;

import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;

import com.ibm.security.modeling.async.AsynchronousTask;
import com.ibm.security.modeling.async.AsynchronousTaskType;
import com.ibm.security.modeling.data.analysis.ModelingManager;
import com.ibm.security.modeling.data.analysis.ProjectManager;
import com.ibm.security.modeling.data.entity.Model;
import com.ibm.security.modeling.data.entity.ModelStatus;
import com.ibm.security.modeling.data.entity.Project;
import com.ibm.security.modeling.i18n.msgs.LogMessages;


public class DeleteProjectTask extends AbstractDeletionTask implements AsynchronousTask
{
    private static final String CLASS_NAME = DeleteProjectTask.class.getName();
    private static final Logger LOG = Logger.getLogger(CLASS_NAME);


    private String projectName;
    private Collection<Model> modelCol;
    private ProjectManager pMgr = null;
    private long projectId = 0L;
    private Project project=null;
    private PlatformTransactionManager txManager;

    public DeleteProjectTask(ProjectManager pMgr, ModelingManager mMgr, long pid)
    {
     super(pMgr.getProject(pid).getName(), mMgr);
     this.project =pMgr.getProject(pid);
     this.projectName = project.getName();
        this.pMgr = pMgr;
        this.projectId = pid;
        this.modelCol=project.getModels();
        this.txManager=(PlatformTransactionManager)SpringUtils.getFactory().getBean("txManager");
    }

    public AsynchronousTaskType getTaskType()
    {
        return AsynchronousTaskType.PROJECT_DELETION;
    }


    public void execute()
    {   
     DefaultTransactionDefinition def = new DefaultTransactionDefinition();
     def.setName("SomeTxName");
     def.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
     TransactionStatus status = txManager.getTransaction(def);
     System.out.println(status.isRollbackOnly());
     boolean success = false;
        try
        {            
         //recordMessage("execute", LogMessages.PROJECT_DELETE_UNDERGOING, new String[]{projectName},1);
            for (Model mo:this.modelCol){
    checkForCancellation();
    //System.out.println("hello");
    //recordMessage("execute", LogMessages.PROJECT_DELETE_UNDERGOING, new String[]{projectName},mo.getId());
    //System.out.println("hello");
    pMgr.deleteModel(projectId,mo.getId());
    System.out.println("66666666666666666666");
            }
            checkForCancellation();
            System.out.println("%%%%%%%%%%%%%%%%%%%%%%");
           // pMgr.deleteModel(, modelId)
            pMgr.deleteProject(projectId);
            System.out.println("$$$$$$$$$$$$$$$$");
           // recordMessage("execute", LogMessages.PROJECT_DELETE_COMPLETE_SUCCESS, 
            //        new String[]{projectName},1L);
            success = true;
            //throw new Exception();
        }
        catch (TaskCanceledException e)
        {
            //Informational message that project creation was canceled

            //recordMessage("execute", LogMessages.PROJECT_DELETE_CANCELED, new String[]{projectName},0L);   
        }
        catch (Throwable t)
        {
            LOG.log(Level.INFO, "caught throwable while deleting project " + projectId, t);
            if (t instanceof IncorrectResultSizeDataAccessException)
            {
                // runtime exception indicating that the project could not be located
                // during the status update or copy process
               // recordErrorMessage("execute", LogMessages.PROJECT_DELETE_FAILED_INTEGRITY, new String[]{projectName},0L);                
            }
            else
            {
                // some other unexpected error occurred - log error
               // recordErrorMessage("execute", LogMessages.PROJECT_DELETE_FAILED_UNKNOWN, new String[]{projectName},0L);                
            }
        }
        finally
        {
            //if not successful, attempt to mark the project as failed
            if (!success)
            {
               System.out.println("i am here4:"+success);
               txManager.rollback(status);
               System.out.println("am");
            }else{
               System.out.println("i am here3:"+success);
               txManager.commit(status);
            }
        }
    }


}

But things are not working as expected..Infact the result each time is also not consistent i.e sometimes the code gets stuck in the bean methods.I am not able to understand whats going on..someone please help

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
Amit Arya
  • 21
  • 1
  • 1
  • 3

1 Answers1

3

You must understand what is going on at the DB level. First of all, since you start a new thread, you must ask Spring for a brand new transaction (i.e. TransactionDefinition.PROPAGATION_REQUIRES_NEW instead of TransactionDefinition.PROPAGATION_NESTED).

That means you must fetch all beans again from the database (because you read them with the first transaction which is no longer valid). This isn't as expensive as it sounds since your cache will still contain them. Just load them again using the ID of the bean you got from the outer transaction. It's usually a good idea to collect all the IDs, close the outer transaction (to get rid of any locks) and then start the inner thread.

Why a new transaction? Because the other thread (which started the delete thread) will eventually complete and close the outer transaction. This is out of the control of the delete thread, so it can happen any time.

If the delete thread hangs than another thread has a lock on one of the beans you try to delete. Enable SQL logging for your ORM framework to see which SQL blocks. That should give you an idea where to look.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • let me share the deletion api as well so that I can get more help @Transactional(propagation=Propagation.REQUIRED) public void deleteProject(long projectId) { jdbc.update(sql.get(PROJECT_DELETE),projectId); } So this method deletes the database contents and I need to control this deletion...from the execute method..by control I mean that I can have the privilege to rollback the database based on the 'success' variable....so considering this please tell me am i thinking right..if not please suggest me a way – Amit Arya Dec 06 '10 at 18:12