我有以下代码:
@Transactional
public void handle() {
for (Item item : getItems()) {
handle(item);
}
}
@Transactional(propagation = Propagation.NESTED)
public void handle(Item item) {
/* logic here */
}
假设handle()
中的循环处理10个项目。还假设对于3个项handle(Item)
将抛出异常。
我的问题:
[1]外部交易是否会在第10项之后提交?这意味着将提交7个项目的必要更改,并且其他3个项目的任何中间更改将在创建时回滚到保存点?
[2] handle(Item)
中的异常是否会被捕获而不会被转发到handle()
呢?这是由@Transactional
完成的吗?
[3]此外,我想了解以下流程的行为差异:
@Transactional
public void handle() {
for (Item item : getItems()) {
handle(item);
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Item item) {
/* logic here */
}
根据我对文档的理解,这里将启动一个新事务,并且将暂停活动事务。这与NESTED
不同,后者创建了保存点并且仍在使用当前事务。但我相信,REQUIRES_NEW
也会提交7个项目的更改,而其他3个项目的任何中间更改都将被遗忘。
那么真正的区别是什么(如果有的话)?
答案 0 :(得分:2)
NESTED开始主要的子交易。 REQUIRES_NEW开始单独交易。
如果使用REQUIRES_NEW标记方法,则无论外部事务发生什么,方法退出数据都保留在DB中(由单独的事务提交)。
如果是NESTED,如果外部事务被回滚,则更改将被回滚。
查看答案here
答案 1 :(得分:1)
根据我对文档的理解,这里将有一个新的交易 已开始,活动交易将被暂停。
A Spring hard fact about transaction management和 WHAT IS A TRANSACTION?
在handle()内部应用handle(Item项)的事务,你应该
@Transactional
public void handle() {
for (Item item : getItems()) {
applicationContext.getBean(your service).handle(item);
}
}
or use spring aspectj load time weaving for self-invocation (inside one service call one method from another)
在循环内使用Propagation.REQUIRES_NEW调用方法,这对性能不利,您为每个调用创建新事务。您可以在一个方法中包装但处理异常 - 仅用于与业务逻辑相关的异常!并非所有类型的例外
@Transactional
public void handle() {
..some logic
//if you really need it
applicationContext.getBean(your service).handleBatch(getItems());
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleBatch(Collection items) {
for (Item item : items) {
applicationContext.getBean(your service).handle(item)
}
}
public void handle(Item item) {
try{
//do operation
}catch(.appropriate type..Exception ex){
//log exception!!!
}
}
@Transactional(的rollbackFor = CheckedException.class)