0

我正在使用 Springs 的 TaskExecutor 类来执行数据库中一些条目的异步删除。所以基本上底层类的执行方法作为线程运行来执行异步删除。

在此方法中,我调用执行删除数据库条目的 bean 方法。我使用PROPAGATION.REQUIRED了 bean 方法中的默认 Transaction 属性。底层是我正在谈论的执行方法。基本上,一旦在 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 方法中。我无法理解发生了什么..有人请帮忙

4

1 回答 1

3

您必须了解数据库级别发生了什么。首先,既然你启动了一个新线程,你必须向 Spring 请求一个全新的事务(即TransactionDefinition.PROPAGATION_REQUIRES_NEW,而不是TransactionDefinition.PROPAGATION_NESTED)。

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

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

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

于 2010-12-06T12:44:52.527 回答