简体   繁体   English

使用Spring的Transaction Manager进行回滚

[英]Rollbacks with Spring's Transaction Manager

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. 我正在使用Springs的TaskExecutor类对数据库中的一些条目执行异步删除操作,因此基本而言,基础类的execute方法作为线程运行以执行异步删除操作。

In this method I call bean methods that perform deletion of database entries. 在此方法中,我调用执行数据库条目删除的bean方法。 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. 我在bean方法中使用的是PROPAGATION.REQUIRED默认Transaction属性。底层是我正在谈论的execute方法。基本上我需要在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);
            }
        }
    }


}

But things are not working as expected..Infact the result each time is also not consistent ie sometimes the code gets stuck in the bean methods.I am not able to understand whats going on..someone please help 但是事情并没有按预期的那样工作。实际上每次的结果也不一致,即有时代码被卡在bean方法中。我无法理解发生了什么。

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 (ie TransactionDefinition.PROPAGATION_REQUIRES_NEW instead of TransactionDefinition.PROPAGATION_NESTED ). 首先,由于您启动了一个新线程,因此必须要求Spring进行全新的事务(即TransactionDefinition.PROPAGATION_REQUIRES_NEW而不是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). 这意味着您必须再次从数据库中获取所有bean(因为您已通过不再有效的第一个事务读取它们)。 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. 只需使用从外部事务中获得的bean的ID重新加载它们。 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. 通常,最好收集所有ID,关闭外部事务(以摆脱任何锁),然后启动内部线程。

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. 如果删除线程挂起,则另一个线程锁定了您尝试删除的一个bean。 Enable SQL logging for your ORM framework to see which SQL blocks. 为您的ORM框架启用SQL日志记录,以查看哪些SQL块。 That should give you an idea where to look. 那应该给您一个想法在哪里看。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM