【发布时间】:2015-05-29 06:53:51
【问题描述】:
我在 JPA 中使用 Spring。我打开了@EnableAsync 和@EnableTransactionManagement。在我的用户注册服务方法中,我调用了一些其他的服务方法,它们被注释为@Async。这些方法可以做各种各样的事情,比如发送欢迎电子邮件和使用我们的第三方支付系统注册新创建的用户。
在我想验证第三方支付系统是否成功创建用户之前,一切正常。此时,@Async 方法会尝试创建一个 UserAccount(它引用新生成的 User)并返回 javax.persistence.EntityNotFoundException: Unable to find com.dk.st.model.User with id 2017 错误
注册调用如下所示:
private User registerUser(User newUser, Boolean waitForAccount) {
String username = newUser.getUsername();
String email = newUser.getEmail();
// ... Verify the user doesn't already exist
// I have tried all manner of flushing and committing right here, nothing works
newUser = userDAO.merge(newUser);
// Here is where we register the new user with the payment system.
// The User we just merged is not /actually/ in the DB
Future<Customer> newCustomer = paymentService.initializeForNewUser(newUser);
// Here is where I occasionally (in test methods) pause this thread to wait
// for the successful account creation.
if (waitForAccount) {
try {
newCustomer.get();
} catch (Exception e) {
logger.error("Exception while creating user account!", e);
}
}
// Do some other things that may or may not be @Aysnc
return newUser;
}
支付服务调用它来完成注册用户的工作,如下所示:
@Async
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Future<Customer> initializeForNewUser(User newUser) {
// ... Set up customerParams
Customer newCustomer = null;
try {
newCustomer = Customer.create(customerParams);
UserAccount newAccount = new UserAccount();
newAccount.setUser(newUser);
newAccount.setCustomerId(newCustomer.getId());
newAccount.setStatus(AccountStatus.PRE_TRIAL);
// When merging, JPA cannot find the newUser object in the DB and complains
userAccountDAO.merge(newAccount);
} catch (Exception e) {
logger.error("Error while creating UserAccount!", e);
throw e;
}
return new AsyncResult<Customer>(newCustomer);
}
列出 here 的 StackOverflow 答案表明我设置了 REQUIRES_NEW 传播,我已经这样做了,但没有这样的运气。
谁能指出我正确的方向?我真的不想直接从我的控制器方法调用 paymentService 。我觉得这肯定是服务级别的调用。
感谢您的帮助!
【问题讨论】:
-
初读时我会说新创建的用户在支付服务执行之前没有刷新
-
我也是这么想的。我在 userDAO.merge() 调用中添加了一个 flush() 调用,以便它使用户立即可用,但没有这样的运气。
@Async@Transactional方法似乎完全在不同的数据库会话中运行。 -
仅供参考:正是正在发生的事情。 @Async 方法调用在不同的线程上处理(这就是异步的意思),根据定义,这意味着不同的事务。
标签: java spring jpa spring-transactions