【问题标题】:Transaction rollbacked previous transaction事务回滚之前的事务
【发布时间】:2017-02-14 01:03:51
【问题描述】:

我在 Spring 中的事务有这种奇怪的行为。

我有两个班级:

首先由 doGenericServiceStuff 调用的服务类(由另一个已经拥有事务的对象):

@Service("myService")
public class ServiceClass {

    public void doGenericServiceStuff(Object someBean){
        BusinessI business = BusinessFactory.getBusinessForObject(someBean); //Here, returns the commonBusinessClass bean 
        business.doGenericBusinessStuff(someBean);
    }

    /*@Transactional (readOnly=false, rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)*/
    public void firstOperation(Object o){
        //multiple database insert and stuff
    }

    /*@Transactional (readOnly=false, rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)*/
    public void secondOperation(Object o){
        //also multiple database insert and stuff
    }
}

然后是调用ServiceClass的一些方法的CommonBusinessClass:

@Bean("commonBusinessClass")
public class CommonBusinessClass implements BusinessI{
    @Autowired
    @Qualifier("myService")
    protected ServiceClass = null;

    @Transactional(rollBackFor=Exception.class, Propagation=Propagation.MANDATORY)
    public Object doGenericBusinessStuff(Object o){
        service.firstOperation(o);
        service.secondOpertion(o);
        //There can be stuff here in other BusinessClass
        return o;
    }
}

免责声明:显然,我不会像那样操纵Objects,也不会调用我的方法doGenericStuff()。但是,ServiceClass 确实调用了 CommonBusinessClass,而后者又调用了 ServiceClass。也许这是糟糕的设计,也许是它不起作用的原因,但这就是我目前所拥有的。

ServiceClass 中的方法不是事务性的(因此是 cmets),而 doGenericBusinessStuff() 是(带有Propagation.MANDATORY)。

新的要求是如果secondOperation() 失败(和回滚)firstOperation() 应该被提交。所以我为firstOperation()secondOperation()添加了@Transactional(评论中的那些)。我期待它能够正常工作(secondOperation() 中的异常不会回滚firstOperation() 中所做的事情),但事实并非如此。但是,如果我删除 doGenericBusinessStuff() 上的 @Transactional,它会起作用。

这种行为是否正常,或者在我的实际应用程序中还有其他一些我没有放在这里的东西(因为我简化了它)?为什么新创建的交易会以任何方式相互关联?对可能发生的事情有任何想法吗?

提前致谢。

【问题讨论】:

    标签: java spring transactions jta


    【解决方案1】:

    您需要了解交易的上下文。如果您将方法标记为事务性,则意味着该方法内的每个操作都将被视为一件事。如果一切正常,则提交事务,但如果出现问题,则回滚整个事务。

    如果你有:

      @Transactional(rollBackFor=Exception.class, Propagation=Propagation.MANDATORY)
        public Object doGenericBusinessStuff(Object o){
            service.firstOperation(o);
            service.secondOpertion(o);
            //There can be stuff here in other BusinessClass
            return o;
        }
    

    因此,如果service.firstOperation(o) 失败,则整个事务将回滚,service.secondOpertion(o) 也是如此。如果service.secondOpertion(o) 失败,doGenericBusinessStuff 内部的所有操作都将被收费。

    编辑:REQUIRES_NEW 在某些情况下可能不起作用,例如,如果您使用 JtaTransactionManager:

    注意:实际的交易暂停不会在开箱即用的情况下起作用 所有事务管理器。这尤其适用于 JtaTransactionManager

    来自http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html

    【讨论】:

    • 好的,所以将 firstOperation 标记为@TransactionalPropagation.REQUIRES_NEW 不会使其成为独立事务(如果doGenereicBusinessStuff() 确实不会回滚)?
    • 如果你使用 Propagation.REQUIRES_NEW 那么 Spring 将创建一个新的独立事务。 byteslounge.com/tutorials/…
    • 但是如果你所有的方法都在同一个类中。 doGenericBusinessStuff 和 firstOperation,则 Spring transactional 不会创建新事务。 Spring 无法隐式处理这种情况。被调用方法上的任何注释都将被忽略(因为调用发生在“this”而不是事务代理上)您需要切换到 AspectJ 来处理这种情况。 stackoverflow.com/questions/28480480/…
    • 是的,但问题是,我在firstOperation() 中添加了@Transactionnal(Propagation.NEW_REQUIERED),当secondOperation 抛出异常时它仍然会回滚。但它不应该,因为它与doGenericBusinessStuff 中声明的交易不同,对吧?但是,如果我从 CommonBusinessClass 中删除 @Transactional(Propagation.MANDATORY),当 secondOperation 抛出异常时,firstOperation() 不会回滚。
    • “注意:实际的事务暂停不会在所有事务管理器上开箱即用。这尤其适用于 JtaTransactionManager”docs.spring.io/spring/docs/current/javadoc-api/org/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2010-11-07
    相关资源
    最近更新 更多