使用Spring的事务管理器回滚

时间:2010-12-06 12:31:11

标签: java transactions springsource

我使用Spring的TaskExecutor类来执行数据库中几个条目的异步删除。基本上,底层类的execute方法作为执行异步删除的线程运行。

在这个方法中,我调用了执行数据库条目删除的bean方法。我在bean方法中使用了PROPAGATION.REQUIRED的默认事务属性。我正在讨论的是执行方法。基本上我需要在callig bean方法之后发生任何异常或者有人取消之后回滚整个数据库事务删除任务。

 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);
            }
        }
    }


}

但事情并没有按预期工作。实际上每次结果也不一致,有时代码会陷入bean方法中。我无法理解最新情况。有人请帮忙

1 个答案:

答案 0 :(得分:3)

您必须了解数据库级别的内容。首先,自从你开始一个新的线程,你必须要求Spring进行全新的交易(即TransactionDefinition.PROPAGATION_REQUIRES_NEW而不是TransactionDefinition.PROPAGATION_NESTED)。

这意味着您必须从数据库中再次获取所有bean (因为您使用不再有效的第一个事务读取它们)。这并不像听起来那么昂贵,因为你的缓存仍然会包含它们。只需使用从外部事务获得的bean的ID再次加载它们。收集所有ID,关闭外部事务(去除任何锁定)然后启动内部线程通常是一个好主意。

为什么要进行新交易?因为另一个线程(启动删除线程)最终将完成并关闭外部事务。这不受删除线程的控制,因此可以随时发生。

如果删除线程挂起,而另一个线程对您尝试删除的其中一个bean有锁定。为ORM框架启用SQL日志记录以查看哪些SQL块。这应该会让你知道在哪里看。