我有一种做一堆事情的方法;其中包括一些插入和更新。它如此宣布......
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public int saveAll(){
//do stuff;
}
它完全按照预期工作,我没有任何问题。然而,有些情况下我想强制回滚,尽管没有例外......目前,当我遇到合适的条件时,我强迫异常,但它很难看,我不喜欢它。
我能以某种方式主动调用回滚吗?这个例外叫它......我想也许我也可以。
答案 0 :(得分:22)
在Spring Transactions中,您使用TransactionStatus.setRollbackOnly()
。
您遇到的问题是您使用@Transactional
来划分交易。这具有非侵入性的好处,但它也意味着如果您想手动与事务上下文交互,则不能。
如果要严格控制事务状态,则必须使用编程事务而不是声明性注释。这意味着使用Spring的TransactionTemplate,或直接使用其PlatformTransactionManager。请参见Spring参考手册的第9.6节。
使用TransactionTemplate
,您提供一个实现TransactionCallback
的回调对象,此回调中的代码可以访问TransactionStatus
个对象。
它不如@Transactional
那么好,但你可以更好地控制你的tx状态。
答案 1 :(得分:16)
我们不使用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
}
}
//
// Annotation definition
//
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface TransactionalWithRollback {
}
//
// 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>
答案 2 :(得分: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;
}
}
setRollbackOnly()
是EJBContext
的成员。 SessionContext
扩展EJBContext
:
http://java.sun.com/j2ee/1.4/docs/api/javax/ejb/SessionContext.html请注意,它仅在会话EJB中可用。
@Resource
是标准的Java EE注释,因此您应该检查Eclipse中的设置。这是example如何使用@Resource
注入SessionContext。
我怀疑这可能不是你的解决方案,因为看起来你可能没有使用EJB - 解释为什么Eclipse没有找到@Resource
。
如果是这种情况,那么您需要直接与交易进行交互 - 请参阅交易模板。
答案 3 :(得分:13)
这对我有用:
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
答案 4 :(得分:3)
你应该让spring注入事务管理器。然后你就可以在它上面调用rollback方法。
答案 5 :(得分:2)
我有使用@Transactional
注释的服务方法。当验证失败,并且我已经有一个附加到当前工作单元的实体时,我使用sessionFactory.getCurrentSession().evict(entity)
来确保没有任何内容写入数据库。这样我就不需要抛出异常。
答案 6 :(得分:0)
是的,我们可以在使用@Transactional(类级别)时强制回滚而不会遇到异常。我们可以简单地抛出一个异常(任何合适的异常)。喜欢
var getParams = function (url) {
var params = {};
var parser = document.createElement('a');
parser.href = url;
var query = parser.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
};
var mylocation ={};
var mylocation = getParams(window.location.href);
console.log(mylocation.prodName);
$('#product').html(mylocation.prodName);
$('#item').html(mylocation.prodItem);
答案 7 :(得分:-3)
抛出异常并按设计使用框架,否则不要使用声明式事务管理并遵循上面的skaffman建议。保持简单。