我有以下存储库:
@Repository
public interface UserRepository extends JpaRepository<User, String> {
Optional<User> findUserByUniqueName(String uniqueName);
}
在集成测试中,首先,我更改了用户实体的uniqueName字段,并将其保存到数据库中。然后,我用mockMvc调用一个端点,并将oldUniqueName添加到请求的头中。
@Test
@Transactional
void test() {
User user =
userRepository.findUserByUniqueName("oldUniqueName").orElse(null);
assertThat(user).isNotNull();
user.setUniqueName("newUniqueName");
userRepository.saveAndFlush(user);
headers = ... // adding oldUniqueName to the headers
mockMvc
.perform(get(endpointUrl).headers(headers))
.andExpect(status().isUnauthorized());
}
然后,自定义安全过滤器会拦截该请求,以便在安全上下文中进行一些修改。在此过滤器中,我从请求标头中提取UniqueName,并尝试在数据库中查找相应的用户:
@Override
@Transactional
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String oldUniqueName = extractUniqueNameFromRequest(request);
try {
User user = userRepository.findUserByUniqueName(oldUniqueName).orElseThrow(new Exception());
// update security context
}
catch(Exception e) {
// handle exception
}
}
我希望使用oldUniqueName对存储库的调用返回一个空的Optional,因此抛出一个异常。但是,奇怪的事情发生了。虽然我正在使用不存在的uniqueName查询数据库(旧的唯一名称),找到了用户实体,但其uniqueName字段的值为“newUniqueName”。我猜它与事务或缓存有关,但无法确定。有人知道我做错了什么吗?
1条答案
按热度按时间qjp7pelc1#
我不完全确定,但是看起来mock mvc请求在它自己的线程中运行,因此事务。由于您没有提交集成测试的事务,mock mvc仍然可以看到旧数据。
如果这个假设是真的,你应该能够通过把集成测试的第一部分放在一个单独的事务中来解决这个问题,你可以通过删除
@Transactional
注解并使用TransactionTemplate
来实现。