想要达成的效果
1、保存订单
2、扣减库存
要求两个操作在同一个方法里面,保存订单使用分布式事务,扣减库存使用使用本地事务,扣减库存失败不会影响保存订单方法,使用多线程完成。
方式一:分布式事务+本地手动事务
适用于调同类的其他方法。
使用Runnable方式演示:
@Override
@Transactional
public int submit(Book book) {
int userId = 100;
String orderId = System.currentTimeMillis() + "" + userId;
Order order = new Order(orderId, new Date(), new BigDecimal("99.9"), 0, userId);
// 保存订单
int result = orderDao.saveOrder(order);
// int a = 10 / 0;
if (result == 1) {
new Thread(() -> {
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW));
try {
reduceStock(book.getId());
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw new RuntimeException(e);
}
}).start();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// if ("Y".equals(submitSwitch)) {
// throw new RuntimeException("回滚,用于对比。userId: " + userId);
// }
return result;
}
// @Transactional // 同类中的方法调用失效
public void reduceStock(int id) {
bookDao.reduceStock(id);
int a = 10 / 0;
}
方式二:分布式事务+@Transactional本地事务
适用于调不同类的方法。
使用CompletableFuture方式演示:
@Override
@Transactional
public int submit(Book book) {
int userId = 100;
String orderId = System.currentTimeMillis() + "" + userId;
Order order = new Order(orderId, new Date(), new BigDecimal("99.9"), 0, userId);
// 1.保存订单
int result = orderDao.saveOrder(order);
// int a = 10 / 0;
if (result == 1) {
// 2. 异步执行库存扣减(独立本地事务)
CompletableFuture.runAsync(() -> {
try {
bookService.reduceStock(book.getId());
} catch (Exception e) {
// 记录日志或进行补偿操作
System.err.println("[Inventory Failed] "+e.getMessage());
}
});
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// if ("Y".equals(submitSwitch)) {
// throw new RuntimeException("回滚,用于对比。userId: " + userId);
// }
return result;
}
使用@Async方式演示:需要配置Spring的Async相关配置
@Override
@Transactional
public int submit(Book book) {
int userId = 100;
String orderId = System.currentTimeMillis() + "" + userId;
Order order = new Order(orderId, new Date(), new BigDecimal("99.9"), 0, userId);
// 保存订单
int result = orderDao.saveOrder(order);
// int a = 10 / 0;
if (result == 1) {
// 2. 异步执行库存扣减(独立本地事务)
bookService.reduceStock(book.getId()); // 使用 @Async
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// if ("Y".equals(submitSwitch)) {
// throw new RuntimeException("回滚,用于对比。userId: " + userId);
// }
return result;
}
@Override
// 独立本地事务(传播级别:REQUIRES_NEW)
@Transactional(
propagation = Propagation.REQUIRES_NEW,
rollbackFor = Exception.class
)
@Async("inventoryThreadPool") // 使用独立线程池
public void reduceStock(Integer id) {
bookDao.reduceStock(id);
int a = 10 / 0;
}
/**
* @Description: 线程池配置类
*/
@Configuration
@EnableAsync
public class ThreadPoolConfig {
@Bean("inventoryThreadPool")
public Executor inventoryThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("inventory-thread-");
executor.initialize();
return executor;
}
}