fix:事务后置回调中开启事务死循环 (#621)
Co-authored-by: zhangpeng <xinniankuailezp@163.com>
This commit is contained in:
parent
700d8c904c
commit
c1f12172e2
@ -61,14 +61,6 @@ public class DsTransactionalTest {
|
||||
PlaceOrderRequest placeOrderRequest = new PlaceOrderRequest(1, 1, 22, OrderStatus.INIT);
|
||||
|
||||
//商品不足
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> orderService.placeOrder(placeOrderRequest));
|
||||
assertThat(placeOrderRequest.getOrderStatus()).isEqualTo(OrderStatus.FAIL);
|
||||
assertThat(orderService.selectOrders()).isEmpty();
|
||||
@ -76,14 +68,6 @@ public class DsTransactionalTest {
|
||||
assertThat(productService.selectProduct()).isEqualTo(new Product(1, 10.0, 20));
|
||||
|
||||
//账户不足
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
placeOrderRequest.setAmount(6);
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.INIT);
|
||||
assertThrows(RuntimeException.class, () -> orderService.placeOrder(placeOrderRequest));
|
||||
@ -93,12 +77,6 @@ public class DsTransactionalTest {
|
||||
assertThat(productService.selectProduct()).isEqualTo(new Product(1, 10.0, 20));
|
||||
|
||||
//正常下单
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.SUCCESS);
|
||||
}
|
||||
});
|
||||
placeOrderRequest.setAmount(5);
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.INIT);
|
||||
assertThat(orderService.placeOrder(placeOrderRequest)).isEqualTo(OrderStatus.INIT);
|
||||
|
@ -17,7 +17,9 @@ package com.baomidou.dynamic.datasource.fixture.v1.service.tx;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.baomidou.dynamic.datasource.tx.TransactionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
@ -40,6 +42,29 @@ public class OrderService {
|
||||
|
||||
@DSTransactional
|
||||
public int placeOrder(PlaceOrderRequest request) {
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
request.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
request.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
request.setOrderStatus(OrderStatus.SUCCESS);
|
||||
}
|
||||
});
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
Integer userId = request.getUserId();
|
||||
Integer productId = request.getProductId();
|
||||
|
@ -61,14 +61,6 @@ public class DsTransactionalTest {
|
||||
PlaceOrderRequest placeOrderRequest = new PlaceOrderRequest(1, 1, 22, OrderStatus.INIT);
|
||||
|
||||
//商品不足
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> orderService.placeOrder(placeOrderRequest));
|
||||
assertThat(placeOrderRequest.getOrderStatus()).isEqualTo(OrderStatus.FAIL);
|
||||
assertThat(orderService.selectOrders()).isEmpty();
|
||||
@ -76,14 +68,6 @@ public class DsTransactionalTest {
|
||||
assertThat(productService.selectProduct()).isEqualTo(new Product(1, 10.0, 20));
|
||||
|
||||
//账户不足
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
placeOrderRequest.setAmount(6);
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.INIT);
|
||||
assertThrows(RuntimeException.class, () -> orderService.placeOrder(placeOrderRequest));
|
||||
@ -93,12 +77,6 @@ public class DsTransactionalTest {
|
||||
assertThat(productService.selectProduct()).isEqualTo(new Product(1, 10.0, 20));
|
||||
|
||||
//正常下单
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.SUCCESS);
|
||||
}
|
||||
});
|
||||
placeOrderRequest.setAmount(5);
|
||||
placeOrderRequest.setOrderStatus(OrderStatus.INIT);
|
||||
assertThat(orderService.placeOrder(placeOrderRequest)).isEqualTo(OrderStatus.INIT);
|
||||
|
@ -17,7 +17,9 @@ package com.baomidou.dynamic.datasource.fixture.v3.service.tx;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.baomidou.dynamic.datasource.tx.TransactionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
@ -40,6 +42,29 @@ public class OrderService {
|
||||
|
||||
@DSTransactional
|
||||
public int placeOrder(PlaceOrderRequest request) {
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
request.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
if (status == STATUS_ROLLED_BACK) {
|
||||
request.setOrderStatus(OrderStatus.FAIL);
|
||||
}
|
||||
}
|
||||
});
|
||||
TransactionContext.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
request.setOrderStatus(OrderStatus.SUCCESS);
|
||||
}
|
||||
});
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
Integer userId = request.getUserId();
|
||||
Integer productId = request.getProductId();
|
||||
|
@ -81,6 +81,9 @@ public class TransactionContext {
|
||||
if (Objects.isNull(synchronization)) {
|
||||
throw new IllegalArgumentException("TransactionSynchronization must not be null");
|
||||
}
|
||||
if (DsStrUtils.isEmpty(TransactionContext.getXID())) {
|
||||
throw new IllegalStateException("Transaction is not active");
|
||||
}
|
||||
Set<TransactionSynchronization> synchs = SYNCHRONIZATION_HOLDER.get();
|
||||
synchs.add(synchronization);
|
||||
}
|
||||
|
@ -113,21 +113,22 @@ public class TransactionalTemplate {
|
||||
boolean state = true;
|
||||
Object o;
|
||||
String xid = LocalTxUtil.startTransaction();
|
||||
boolean shouldInvokeAction = TransactionContext.getSynchronizations().isEmpty();
|
||||
try {
|
||||
o = transactionalExecutor.execute();
|
||||
} catch (Exception e) {
|
||||
state = !isRollback(e, transactionInfo);
|
||||
throw e;
|
||||
} finally {
|
||||
invokeBeforeCompletion();
|
||||
invokeBeforeCompletion(shouldInvokeAction);
|
||||
if (state) {
|
||||
invokeBeforeCommit();
|
||||
invokeBeforeCommit(shouldInvokeAction);
|
||||
LocalTxUtil.commit(xid);
|
||||
invokeAfterCommit();
|
||||
invokeAfterCompletion(TransactionSynchronization.STATUS_COMMITTED);
|
||||
invokeAfterCommit(shouldInvokeAction);
|
||||
invokeAfterCompletion(TransactionSynchronization.STATUS_COMMITTED, shouldInvokeAction);
|
||||
} else {
|
||||
LocalTxUtil.rollback(xid);
|
||||
invokeAfterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
|
||||
invokeAfterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK, shouldInvokeAction);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
@ -241,8 +242,8 @@ public class TransactionalTemplate {
|
||||
/**
|
||||
* Invoke before commit.
|
||||
*/
|
||||
public void invokeBeforeCommit() {
|
||||
if (shouldInvokeAction()) {
|
||||
public void invokeBeforeCommit(boolean shouldInvokeAction) {
|
||||
if (shouldInvokeAction) {
|
||||
for (TransactionSynchronization synchronization : TransactionContext.getSynchronizations()) {
|
||||
synchronization.beforeCommit(false);
|
||||
}
|
||||
@ -252,8 +253,8 @@ public class TransactionalTemplate {
|
||||
/**
|
||||
* Invoke before completion .
|
||||
*/
|
||||
public void invokeBeforeCompletion() {
|
||||
if (shouldInvokeAction()) {
|
||||
public void invokeBeforeCompletion(boolean shouldInvokeAction) {
|
||||
if (shouldInvokeAction) {
|
||||
for (TransactionSynchronization synchronization : TransactionContext.getSynchronizations()) {
|
||||
synchronization.beforeCompletion();
|
||||
}
|
||||
@ -263,8 +264,8 @@ public class TransactionalTemplate {
|
||||
/**
|
||||
* Invoke after commit.
|
||||
*/
|
||||
public void invokeAfterCommit() {
|
||||
if (shouldInvokeAction()) {
|
||||
public void invokeAfterCommit(boolean shouldInvokeAction) {
|
||||
if (shouldInvokeAction) {
|
||||
for (TransactionSynchronization synchronization : TransactionContext.getSynchronizations()) {
|
||||
synchronization.afterCommit();
|
||||
}
|
||||
@ -274,22 +275,12 @@ public class TransactionalTemplate {
|
||||
/**
|
||||
* Invoke after completion.
|
||||
*/
|
||||
public void invokeAfterCompletion(int status) {
|
||||
if (shouldInvokeAction()) {
|
||||
public void invokeAfterCompletion(int status, boolean shouldInvokeAction) {
|
||||
if (shouldInvokeAction) {
|
||||
for (TransactionSynchronization synchronization : TransactionContext.getSynchronizations()) {
|
||||
synchronization.afterCompletion(status);
|
||||
}
|
||||
TransactionContext.removeSynchronizations();
|
||||
}
|
||||
TransactionContext.removeSynchronizations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should invoke action boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean shouldInvokeAction() {
|
||||
//If there is a savepoint, the action should not be executed
|
||||
return !ConnectionFactory.hasSavepoint(TransactionContext.getXID());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user