有没有办法强制事务回滚而不遇到异常?

Gen*_* S. 38 java spring hibernate

我有一个做一堆事情的方法; 其中包括一些插入和更新.它如此宣布......

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public int saveAll(){
 //do stuff;
}
Run Code Online (Sandbox Code Playgroud)

它完全按照预期工作,我没有任何问题.然而,有些情况下我想强制回滚,尽管没有例外......目前,当我遇到合适的条件时,我强迫异常,但它很难看,我不喜欢它.

我可以以某种方式主动调用回滚吗?这个例外叫它......我想也许我也可以.

ska*_*man 24

在Spring Transactions中,您使用TransactionStatus.setRollbackOnly().

你在这里遇到的问题是你@Transactional用来划分你的交易.这具有非侵入性的好处,但它也意味着如果您想手动与事务上下文交互,则不能.

如果要严格控制事务状态,则必须使用编程事务而不是声明性注释.这意味着使用Spring的TransactionTemplate,或直接使用其PlatformTransactionManager.请参见Spring参考手册的第9.6节.

使用TransactionTemplate,您提供一个实现的回调对象TransactionCallback,并且此回调中的代码可以访问这些TransactionStatus对象.

它不是那么好@Transactional,但你可以更好地控制你的tx状态.

  • 使用`TransactionInterceptor.currentTransactionStatus().setRollbackOnly()`是一种在使用`@Transactional`的方法中手动与事务交互的方法吗?主要用于替换`setRollbackOnly` EJB方法.如果您对此有评论,我们会感兴趣.谢谢! (5认同)

Jak*_*kub 17

我们不使用EJB,而是简单的Spring,我们选择了AOP方法.我们已经实现了新的注释,@TransactionalWithRollback并使用AOP用"around"建议包装带注释的方法.实施我们提到的建议TransactionTemplate.这意味着一开始就做了一点工作,但结果我们可以@TransactionalWithRollback像我们@Transactional在其他情况下使用的那样注释一个方法.主要代码看起来干净简单.

//
// Service class - looks nice
//
class MyServiceImpl implements MyService {
    @TransactionalWithRollback
    public int serviceMethod {
        // DO "read only" WORK
    }
}
Run Code Online (Sandbox Code Playgroud)
//
// Annotation definition
//
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface TransactionalWithRollback {
}
Run Code Online (Sandbox Code Playgroud)
//
// the around advice implementation
//
public class TransactionalWithRollbackInterceptor {
    private TransactionTemplate txTemplate;
    @Autowired private void setTransactionManager(PlatformTransactionManager txMan) {
        txTemplate = new TransactionTemplate(txMan);
    }

    public Object doInTransactionWithRollback(final ProceedingJoinPoint pjp) throws Throwable {
        return txTemplate.execute(new TransactionCallback<Object>() {
            @Override public Object doInTransaction(TransactionStatus status) {
                status.setRollbackOnly();
                try {
                    return pjp.proceed();
                } catch(RuntimeException e) {
                    throw e;
                } catch (Throwable e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)
//
// snippet from applicationContext.xml:
//
<bean id="txWithRollbackInterceptor" class="net.gmc.planner.aop.TransactionalWithRollbackInterceptor" />

<aop:config>
    <aop:aspect id="txWithRollbackAspect" ref="txWithRollbackInterceptor">
        <aop:pointcut 
            id="servicesWithTxWithRollbackAnnotation" 
            expression="execution( * org.projectx..*.*(..) ) and @annotation(org.projectx.aop.TransactionalWithRollback)"/>
        <aop:around method="doInTransactionWithRollback" pointcut-ref="servicesWithTxWithRollbackAnnotation"/>
    </aop:aspect>
</aop:config>
Run Code Online (Sandbox Code Playgroud)

  • +1 花时间回答我 4 年前提出的问题,该问题已经有多个赞成票接受的答案!:) (2认同)

小智 16

这对我有用:

TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
Run Code Online (Sandbox Code Playgroud)


Edw*_*ges 15

如果您在EJB中,请调用setRollbackOnly()SessionContext.

你可以这样注射SessionContext:

public MyClass {
    @Resource
    private SessionContext sessionContext;

    @Transactional(propagation = Propagation.REQUIRED, 
                   isolation = Isolation.DEFAULT, 
                   readOnly = false)
    public int saveAll(){
        //do stuff;
        if(oops == true) {
             sessionContext.setRollbackOnly();
             return;
        }
    }
Run Code Online (Sandbox Code Playgroud)

setRollbackOnly()是...的成员EJBContext. SessionContext扩展EJBContext:http: //java.sun.com/j2ee/1.4/docs/api/javax/ejb/SessionContext.html 注意它只在会话EJB中可用.

@Resource是标准的Java EE注释,因此您应该检查Eclipse中的设置.这是一个如何使用注入SessionContext 的示例@Resource.

我怀疑这可能不是你的解决方案,因为看起来你可能没有使用EJB - 解释为什么Eclipse没有找到@Resource.

如果是这种情况,那么您将需要直接与事务交互 - 请参阅事务模板.


Rug*_*ggs 5

您应该让 spring 注入事务管理器。然后你可以调用回滚方法就可以了。