如何将我的用户创建方法限制为一次交易? (容器与事务管理并发)
How to limit my user creation method to one transaction at the time? (Container vs Transaction managed Concurrency)
我正在使用 ContainerRequestFilter 检查用户是否已存在于我的数据库中。 如果没有,它调用一个服务来创建它:
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationRequestFilter implements ContainerRequestFilter {
// [...]
@Inject
JsonWebToken jwt;
@Override
public void filter(ContainerRequestContext containerRequestContext) {
UserAccount userAccount = userAccountService.createIfNotExistsBySubjectId(jwt.getSubject());
}
}
}
服务 bean:
@RequestScoped
public class UserAccountService {
// [...]
@Transactional
public UserAccount createIfNotExistsBySubjectId(String subjectId) {
UserAccount userAccount = UserAccount.find("subjectId", subjectId).withLock(LockModeType.PESSIMISTIC_WRITE).firstResult();
if (userAccount == null) {
log.info(MessageFormat.format("Creating new user account for subjectId {0}.", subjectId));
UserAccount userAccount = new UserAccount(subjectId)
userAccount.persistAndFlush();
}
return userAccount;
}
}
因此,我在同时发送多个请求时遇到了竞争条件。两个线程正在调用我的方法:
...导致明显的 SQL 错误:
为了解决这个问题,我尝试了两种方法:
Quarkus Panache Documentation 声明我可以锁定查找操作 - 因此我的服务中 LockModeType.PESSIMISTIC_WRITE。
Quarkus CDI Documentation 声明我可以通过使用注释 io.quarkus.arc.Lock 强制执行 容器管理的并发 。我尝试将它应用于我的 createIfNotExistsBySubjectId,但无济于事。
我做错了什么?
我想确保以阻塞方式调用用户创建方法。
任何时候你对远程系统进行 read/check/update 操作,你都会遇到这样的问题。
您需要做的是利用数据库的“upsert”功能。请参阅 了解如何在 PostgreSQL
中创建正确的查询
我正在使用 ContainerRequestFilter 检查用户是否已存在于我的数据库中。 如果没有,它调用一个服务来创建它:
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationRequestFilter implements ContainerRequestFilter {
// [...]
@Inject
JsonWebToken jwt;
@Override
public void filter(ContainerRequestContext containerRequestContext) {
UserAccount userAccount = userAccountService.createIfNotExistsBySubjectId(jwt.getSubject());
}
}
}
服务 bean:
@RequestScoped
public class UserAccountService {
// [...]
@Transactional
public UserAccount createIfNotExistsBySubjectId(String subjectId) {
UserAccount userAccount = UserAccount.find("subjectId", subjectId).withLock(LockModeType.PESSIMISTIC_WRITE).firstResult();
if (userAccount == null) {
log.info(MessageFormat.format("Creating new user account for subjectId {0}.", subjectId));
UserAccount userAccount = new UserAccount(subjectId)
userAccount.persistAndFlush();
}
return userAccount;
}
}
因此,我在同时发送多个请求时遇到了竞争条件。两个线程正在调用我的方法:
...导致明显的 SQL 错误:
为了解决这个问题,我尝试了两种方法:
Quarkus Panache Documentation 声明我可以锁定查找操作 - 因此我的服务中 LockModeType.PESSIMISTIC_WRITE。
Quarkus CDI Documentation 声明我可以通过使用注释 io.quarkus.arc.Lock 强制执行 容器管理的并发 。我尝试将它应用于我的 createIfNotExistsBySubjectId,但无济于事。
我做错了什么? 我想确保以阻塞方式调用用户创建方法。
任何时候你对远程系统进行 read/check/update 操作,你都会遇到这样的问题。
您需要做的是利用数据库的“upsert”功能。请参阅 了解如何在 PostgreSQL
中创建正确的查询