Java 有没有一种方法可以在不遇到异常的情况下强制事务回滚?

Java 有没有一种方法可以在不遇到异常的情况下强制事务回滚?,java,hibernate,spring,Java,Hibernate,Spring,我有一种方法可以做很多事情;其中,他们做了大量的插入和更新。是这样宣布的 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false) public int saveAll(){ //do stuff; } 它的工作原理与预期完全一致,我对此没有任何问题。然而,在某些情况下,我想强制回滚,尽管没有异常。。。目前,当我遇到合适的条件时,我会强制执行一个异常,

我有一种方法可以做很多事情;其中,他们做了大量的插入和更新。是这样宣布的

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public int saveAll(){
 //do stuff;
}
它的工作原理与预期完全一致,我对此没有任何问题。然而,在某些情况下,我想强制回滚,尽管没有异常。。。目前,当我遇到合适的条件时,我会强制执行一个异常,但这很难看,我不喜欢

我可以主动调用回滚吗?异常称之为。。。我想我也可以。

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

您可以像这样插入
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;
        }
    }
setRollbackOnly()
EJBContext
的成员
SessionContext
extends
EJBContext
: 注意,它仅在会话EJB中可用

@Resource
是标准的JavaEE注释,因此您可能应该在Eclipse中检查您的设置。下面是如何使用
@Resource
注入SessionContext的示例

我怀疑这可能不是您的解决方案,因为您可能没有使用EJB——这解释了为什么Eclipse没有找到
@Resource


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

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

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

这里的问题是您正在使用
@Transactional
来划分事务。这具有非侵入性的优点,但也意味着如果您想手动与事务上下文交互,则不能

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

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


它不像
@Transactional
那么好,但是您可以更紧密地控制您的发送状态

抛出异常并按设计使用框架,否则不要使用声明性事务管理并遵循上面的skaffman建议。保持简单。

我有带有
@Transactional
注释的服务方法。当验证失败,并且我已经有一个实体连接到当前工作单元时,我使用
sessionFactory.getCurrentSession().execute(entity)
确保没有任何内容写入数据库。这样我就不需要抛出异常。

我们不使用EJB,而是使用SimpleSpring,我们选择了AOP方法。 我们已经实现了新的注释
@TransactionalWithRollback
,并使用AOP用“环绕”建议包装那些注释过的方法。为了实现建议,我们使用前面提到的
TransactionTemplate
。这意味着在开始时需要做一些工作,但结果是我们可以像在其他情况下使用
@Transactional
一样,使用
@Transactional Withrollback
注释一个方法。主代码看起来简洁明了

//
// Service class - looks nice
//
class MyServiceImpl implements MyService {
    @TransactionalWithRollback
    public int serviceMethod {
        // DO "read only" WORK
    }
}


//
//关于实施的建议
//
公共类TransactionalWithRollbackInterceptor{
私有事务模板txTemplate;
@自动连线专用void setTransactionManager(PlatformTransactionManager txMan){
txTemplate=新事务处理模板(txMan);
}
公共对象doInTransactionWithRollback(最终处理连接点pjp)抛出可丢弃{
返回txTemplate.execute(newTransactionCallback()){
@覆盖公共对象doInTransaction(TransactionStatus状态){
status.setRollbackOnly();
试一试{
返回pjp.procedure();
}捕获(运行时异常e){
投掷e;
}捕获(可丢弃的e){
抛出新的运行时异常(e);
}
}
});
}
}

//
//applicationContext.xml中的代码段:
//
这对我很有用:

TransactionInterceptor.currentTransactionStatus().setRollbackOnly();

是的,我们可以在使用@Transactional(类级别)时强制回滚,而不会遇到异常。我们可以简单地抛出一个异常(任何合适的异常)。像


这似乎是正确的选择。。。我现在正在调查SavepointManager。这导致在“事务回滚,因为它已被标记为仅回滚”结束时引发异常。Eclipse不将@Resource识别为注释,并且setRollbackOnly()不是SessionContext的成员(当它从org.springframework.orm.hibernate3.SpringSessionContext导入时). 所以我更接近了,但还不够接近:)请查看第9.5.3+1节,了解我花时间回答了一个问题,这个问题是我4年前提出的,并且已经有多个被接受的答案了!:)我喜欢的东西是完整的:-)将使用<代码>事务性拦截程序。主要用于替换
setRollbackOnly
EJB方法。如果您对此有何评论,我将非常感兴趣。谢谢在长会话中,这可能是一个折衷的解决方案。
我们可以简单地抛出一个异常(任何合适的)
实际上Spring中的默认设置是回滚必须是RuntimeException
//
// 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);
                }
            }
        });
    }
}
//
// 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>
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
if(some condition matches){
 throw new DataIntegrityViolationException("Rollback Tnx.. Since ..." );
}