我希望你一切都好。
我想找到最好的方法来确保在事务外部调用服务方法。如下:
让我们说我们有一种形式为:
的方法@Transactional
public void insertEntity(Entity entity){
persistence.save(entity);
}
现在,可以说我们正在调用此方法,但是我们需要确保不会在已经具有事务性的内部代码中调用该方法。以下是错误的:
@Transactional
public void enclosingTransaction() {
//Perform long process transaction
service.insertEntity(entity);
}
什么是使我们的方法“ insertEntity”了解正在运行的事务内被调用并引发错误的最佳选择?
谢谢!
答案 0 :(得分:0)
您可以调用TransactionAspectSupport.currentTransactionStatus().isNewTransaction()
方法以了解当前事务是否是新的(即,它不是从另一个@Transactional
方法传播的):
@Transactional
public void insertEntity(Entity entity){
if (!TransactionAspectSupport.currentTransactionStatus().isNewTransaction()) {
throw new IllegalStateException("Transaction is not new!");
}
persistence.save(entity);
}
静态方法TransactionAspectSupport.currentTransactionStatus()
返回一个TransactionStatus
对象,该对象表示当前方法调用的事务状态。
我编写了一个最小的Spring MVC Web应用程序来测试您的情况(我省略了配置类和文件以及import
和package
的声明):
TestController.java
@RestController
public class TestController {
private static final Logger log = LoggerFactory.getLogger(TestController.class);
@Autowired
private ServiceOne serviceOne;
@Autowired
private ServiceTwo serviceTwo;
@GetMapping(path = "/test-transactions")
public String testTransactions() {
log.info("*** TestController.testTransactions() ***");
log.info("* Invoking serviceOne.methodOne()...");
try {
serviceOne.methodOne();
}
catch (IllegalStateException e) {
log.error("* {} invoking serviceOne.methodOne()!", e.getClass().getSimpleName());
}
log.info("* Invoking serviceTwo.methodTwo()...");
try {
serviceTwo.methodTwo();
}
catch (IllegalStateException e) {
log.error("* {} invoking serviceTwo.methodTwo()!", e.getClass().getSimpleName());
}
return "OK";
}
}
ServiceOneImpl.java
@Service
public class ServiceOneImpl implements ServiceOne {
private static final Logger log = LoggerFactory.getLogger(ServiceOneImpl.class);
@Autowired
private ServiceTwo serviceTwo;
@PersistenceContext
private EntityManager em;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void methodOne() {
log.info("*** ServiceOne.methodOne() ***");
log.info("getCurrentTransactionName={}", TransactionSynchronizationManager.getCurrentTransactionName());
log.info("isNewTransaction={}", TransactionAspectSupport.currentTransactionStatus().isNewTransaction());
log.info("Query result={}", em.createNativeQuery("SELECT 1").getResultList());
log.info("getCurrentTransactionName={}", TransactionSynchronizationManager.getCurrentTransactionName());
log.info("isNewTransaction={}", TransactionAspectSupport.currentTransactionStatus().isNewTransaction());
serviceTwo.methodTwo();
}
}
ServiceTwoImpl.java
@Service
public class ServiceTwoImpl implements ServiceTwo {
private static final Logger log = LoggerFactory.getLogger(ServiceTwoImpl.class);
@PersistenceContext
private EntityManager em;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void methodTwo() {
log.info("*** ServiceTwo.methodTwo() ***");
log.info("getCurrentTransactionName={}", TransactionSynchronizationManager.getCurrentTransactionName());
log.info("isNewTransaction={}", TransactionAspectSupport.currentTransactionStatus().isNewTransaction());
if (!TransactionAspectSupport.currentTransactionStatus().isNewTransaction()) {
log.warn("Throwing exception because transaction is not new...");
throw new IllegalStateException("Transaction is not new!");
}
log.info("Query result={}", em.createNativeQuery("SELECT 2").getResultList());
log.info("getCurrentTransactionName={}", TransactionSynchronizationManager.getCurrentTransactionName());
log.info("isNewTransaction={}", TransactionAspectSupport.currentTransactionStatus().isNewTransaction());
}
}
这是执行的日志:
INFO test.transactions.web.TestController - *** TestController.testTransactions() ***
INFO test.transactions.web.TestController - * Invoking serviceOne.methodOne()...
INFO test.transactions.service.ServiceOneImpl - *** ServiceOne.methodOne() ***
INFO test.transactions.service.ServiceOneImpl - getCurrentTransactionName=test.transactions.service.ServiceOneImpl.methodOne
INFO test.transactions.service.ServiceOneImpl - isNewTransaction=true
INFO test.transactions.service.ServiceOneImpl - Query result=[1]
INFO test.transactions.service.ServiceOneImpl - getCurrentTransactionName=test.transactions.service.ServiceOneImpl.methodOne
INFO test.transactions.service.ServiceOneImpl - isNewTransaction=true
INFO test.transactions.service.ServiceTwoImpl - *** ServiceTwo.methodTwo() ***
INFO test.transactions.service.ServiceTwoImpl - getCurrentTransactionName=test.transactions.service.ServiceOneImpl.methodOne
INFO test.transactions.service.ServiceTwoImpl - isNewTransaction=false
WARN test.transactions.service.ServiceTwoImpl - Throwing exception because transaction is not new...
ERROR test.transactions.web.TestController - * IllegalStateException invoking serviceOne.methodOne()!
INFO test.transactions.web.TestController - * Invoking serviceTwo.methodTwo()...
INFO test.transactions.service.ServiceTwoImpl - *** ServiceTwo.methodTwo() ***
INFO test.transactions.service.ServiceTwoImpl - getCurrentTransactionName=test.transactions.service.ServiceTwoImpl.methodTwo
INFO test.transactions.service.ServiceTwoImpl - isNewTransaction=true
INFO test.transactions.service.ServiceTwoImpl - Query result=[2]
INFO test.transactions.service.ServiceTwoImpl - getCurrentTransactionName=test.transactions.service.ServiceTwoImpl.methodTwo
INFO test.transactions.service.ServiceTwoImpl - isNewTransaction=true