Spring Boot保存后MongoDB的DBRef字段roles为空问题排查
问题
我定义了User和Role两个模型,代码如下:
User模型:
@Document("user") @Data @NoArgsConstructor @AllArgsConstructor public class User { @Id private String id; private String name; private String username; private String password; @DBRef private Collection<Role> roles = new ArrayList<>(); }
Role模型:
@Document("role") @Data @NoArgsConstructor @AllArgsConstructor public class Role { @Id private String id; private String name; }
同时实现了保存用户、保存角色、为用户添加角色的三个方法:
@Override public User saveUser(User user) { log.info("Saving new user {} to the database", user.getName()); return userRepository.save(user); } @Override public Role saveRole(Role role) { log.info("Saving new role {} to the database", role.getName()); return roleRepository.save(role); } @Override public void addRoleToUser(String username, String roleName) { log.info("Adding role {} to user {}", roleName, username); User user = userRepository.findByUsername(username); Role role = roleRepository.findByName(roleName); user.getRoles().add(role); }
通过CommandLineRunner初始化数据:
@Bean CommandLineRunner run(UserService userService) { return args -> { userService.saveRole(new Role(null, "ROLE_USER")); userService.saveRole(new Role(null, "ROLE_ADMIN")); userService.saveUser(new User(null,"Stefan", "stefanadmin", "stefanadmin", new ArrayList<>())); userService.saveUser(new User(null,"Marko", "markoadmin", "markoadmin", new ArrayList<>())); userService.saveUser(new User(null,"Jovan", "jovanobicanuser", "jovanobicanuser", new ArrayList<>())); userService.addRoleToUser("stefanadmin", "ROLE_ADMIN"); userService.addRoleToUser("stefanadmin", "ROLE_USER"); userService.addRoleToUser("markoadmin", "ROLE_ADMIN"); userService.addRoleToUser("jovanobicanuser", "ROLE_USER"); }; }
所有操作执行正常,但返回用户数据时,roles字段为空数组,示例JSON:
{"id":"6331bda42c1fa17e41079c99","name":"Jovan","username":"jovanobicanuser","password":"jovanobicanuser","roles":[]}
教程使用MySQL而我使用MongoDB,推测问题出在关联方式上,请问可能的原因是什么?
分析与解决
原因1:添加角色后未持久化用户修改
MongoDB不会像MySQL那样自动同步内存中实体的修改,你在addRoleToUser方法里给用户添加角色后,没有调用userRepository.save(user)将修改保存到数据库,导致数据库中的用户角色列表仍是空的,查询自然返回空数组。
修改后的addRoleToUser方法:
@Override public void addRoleToUser(String username, String roleName) { log.info("Adding role {} to user {}", roleName, username); User user = userRepository.findByUsername(username); Role role = roleRepository.findByName(roleName); user.getRoles().add(role); userRepository.save(user); // 新增该行,持久化用户的角色修改 }
原因2:@DBRef默认懒加载未触发关联加载
MongoDB的@DBRef注解默认是懒加载模式,如果查询用户时没有显式触发关联数据的加载,返回的User对象中roles字段会是空数组。可以通过两种方式解决:
- 在用户查询方法上添加
@Query(fields = "{'roles': 1}"),显式指定加载roles字段; - 或者修改
@DBRef注解为立即加载:
@DBRef(lazy = false) private Collection<Role> roles = new ArrayList<>();
原因3:初始化数据时的引用有效性问题(概率较低)
虽然当前初始化顺序是先存角色再存用户,但如果角色的保存未完成就去关联,可能导致引用无效。可以调整初始化代码,确保使用保存后返回的角色实例进行关联:
@Bean CommandLineRunner run(UserService userService) { return args -> { // 先保存角色并获取实例 Role userRole = userService.saveRole(new Role(null, "ROLE_USER")); Role adminRole = userService.saveRole(new Role(null, "ROLE_ADMIN")); // 保存用户并获取实例 User stefan = userService.saveUser(new User(null,"Stefan", "stefanadmin", "stefanadmin", new ArrayList<>())); User marko = userService.saveUser(new User(null,"Marko", "markoadmin", "markoadmin", new ArrayList<>())); User jovan = userService.saveUser(new User(null,"Jovan", "jovanobicanuser", "jovanobicanuser", new ArrayList<>())); // 关联角色后重新保存用户 stefan.getRoles().add(adminRole); stefan.getRoles().add(userRole); userService.saveUser(stefan); marko.getRoles().add(adminRole); userService.saveUser(marko); jovan.getRoles().add(userRole); userService.saveUser(jovan); }; }
内容的提问来源于stack exchange,提问作者Stefan Jankovic
相关产品推荐
相关产品推荐

