Spring Boot 异步事务回滚问题

huangapple go评论57阅读模式
英文:

Spring Boot Async Transaction Rollback Issue

问题

methodC中出现了问题并引发了异常,因此我想要回滚存储在methodAsaveTableA中的数据,这是同步部分的一部分。目前回滚没有发生。请指导我。

英文:

Facing 1 strange issue in spring boot @Async and @Transactional, following is sample code:

ServiceA

@Transactional
public ResponseA methodA() {
	try {
		// some code
		saveTableA() //save some data to tableA
		serviceB.methodB();
	} catch(Exception e) {
		e.printStacktrace();
	}
	return response;
}

ServiceB

@Async
public void methodB() {
	try {
		// some code
		serviceC.methodC();
		save some data to tableB
	} catch(Exception e) {
		e.printStacktrace();
		throw new ServiceException(ex.getMessage());
	}
}

ServiceC

public void methodC() throws Exception {
	try {
		// some code
		call to another service // this is failing sometime
	} catch(Exception e) {
		e.printStacktrace();
		throw e;
	}
}

now in methodC there is some issue and exception occur, so I want to rollback data stored in methodA's saveTableA, which is part of synchronous part.
Rollback is currently not happening.
Please guide me.

答案1

得分: 1

因为您使methodCmethodA异步执行,当methodC抛出异常时,methodA可能已经完成并提交了事务。

如果您希望依赖@Transactional来回滚,那么methodA必须在methodC之后完成。如果是这种情况,那么让methodC异步执行就没有意义。

如果您必须使methodCmethodA异步执行,那么您只能选择手动回滚。在methodC中启动一个事务,在methodC捕获异常后撤销methodA所做的操作。

英文:

Because you make methodC executes asynchronously with methodA , it is possible that when methodC throws exception , methodA already completed and committed the transaction.

If you want to relies on @Transactional to rollback, methodA have to complete after methodC . So there is no points to make methodC executes asynchronously if this is the case.

If you must make methodC to execute asynchronously with methodA , you have no choices but only can manually rollback by yourself . Start a transaction in methodC to undo what are done by methodA after you catch exception in methodC.

答案2

得分: 0

ServiceA:

@Transactional
public ResponseA methodA() {
    try {
        // 一些代码
        saveTableA() // 将一些数据保存到表A
        serviceB.methodB();
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
    return response;
}

ServiceB:

@Async
public Future<?> methodB() {
    try {
        // 一些代码
        serviceC.methodC();
        // 将一些数据保存到表B
    } catch(Exception e) {
       return AsyncResult.forExecutionException(e);
    }
    return new AsyncResult<>(null);
}
英文:

You need to adjust your code like below

ServiceA:

@Transactional
public ResponseA methodA() {
    try {
        // some code
        saveTableA() //save some data to tableA
        serviceB.methodB();
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
    return response;
}

ServiceB:

@Async
public Future&lt;?&gt; methodB() {
    try {
        // some code
        serviceC.methodC();
        save some data to tableB
    } catch(Exception e) {
       return AsyncResult.forExecutionException(e);
    }
    return new AsyncResult&lt;&gt;(null);
}

huangapple
  • 本文由 发表于 2023年2月27日 13:15:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75576967.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定