Spring + Mongodb 与 Null id 问题
Posted
技术标签:
【中文标题】Spring + Mongodb 与 Null id 问题【英文标题】:Spring + Mongodb with a Null id Issue 【发布时间】:2019-02-26 22:45:48 【问题描述】:我正在使用 Spring + MongoDB 进行学术项目
我有三个文档
用户.java
@Document
public class User implements UserDetails, Serializable
private static final long SerialVersionUID = 147147L;
@Id
private String id;
private String username;
private String password;
private String firstname;
private String lastname;
private String email;
private String phone;
private boolean enable = true;
private Set<UserRole> userRoles = new HashSet<>();
...
角色.java
@Document
public class Role implements Serializable
private static final long SerialVersionUID = 456456L;
@Id
private String id;
private String name;
...
UserRole.java
@Document(collection = "user_roles")
public class UserRole implements Serializable
private static final long SerialVersionUID = 789789L;
@Id
private String id;
@DBRef
private User user;
@DBRef
private Role role;
private String name;
...
还有一个 UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService
private static final Logger LOG = LoggerFactory.getLogger(UserService.class);
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
UserRoleRepository userRoleRepository;
@Override
public User createUser(User user, Set<UserRole> userRoles)
User localUser = userRepository.findByUsername(user.getUsername());
if(localUser != null)
LOG.info("User with username already exist. Nothing will be done. ", user.getUsername());
else
for (UserRole ur : userRoles)
roleRepository.save(ur.getRole());
//here is the problem: the userrole instance created cannot generate Id
userRoleRepository.save(ur);
user.getUserRoles().addAll(userRoles);
localUser = userRepository.save(user);
return localUser;
还有 DemoApplication.java
@SpringBootApplication
public class DemoApplication implements CommandLineRunner
@Autowired
UserService userService;
public static void main(String[] args)
SpringApplication.run(DemoApplication.class, args);
@Override
public void run(String... args) throws Exception
User user1 = new User();
user1.setFirstname("John");
user1.setLastname("Adams");
user1.setUsername("j");
user1.setPassword(SecurityUtility.passwordEncoder().encode("p"));
user1.setEmail("JAdams@gmail.com");
Set<UserRole> userRoles = new HashSet<>();
Role role1 = new Role();
role1.setName("ROLE_USER");
UserRole userRole1 = new UserRole();
userRole1.setRole(role1);
userRole1.setUser(user1);
userRoles.add(userRole1);
userService.createUser(user1, userRoles);
和 ExceptionStackTrack
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:821) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:802) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:341) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1277) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1265) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at com.example.demo.DemoApplication.main(DemoApplication.java:22) [classes/:na]
Caused by: org.springframework.data.mapping.MappingException: Cannot create a reference to an object with a NULL id.
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createDBRef(MappingMongoConverter.java:936) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:554) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeAssociation(MappingMongoConverter.java:517) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:494) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:481) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:455) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:399) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.toDocument(MongoTemplate.java:1071) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:1254) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:1202) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:82) ~[spring-data-mongodb-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:641) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at com.sun.proxy.$Proxy73.save(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at com.sun.proxy.$Proxy73.save(Unknown Source) ~[na:na]
at com.example.demo.Service.Impl.UserServiceImpl.createUser(UserServiceImpl.java:42) ~[classes/:na]
at com.example.demo.DemoApplication.run(DemoApplication.java:46) [classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:818) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
... 5 common frames omitted
这里我不知道为什么角色和用户实例可以自动生成而用户角色不能。控制台向我返回 Id 为 NULL 且不能被引用的异常。
我是新手,希望有人能给我答案。
谢谢。
【问题讨论】:
请包含异常堆栈跟踪 好的,我添加了异常堆栈跟踪 【参考方案1】:您似乎在调用userRoleRepository.save(ur)
,以防数据库中不存在具有所提供用户名的User
并且在实际存储此User
之前。
我相信你应该重新组织你的代码,首先存储User
,然后用这个User
集合存储UserRole
。
换句话说(代码?),在您的UserServiceImpl
中,您可以尝试执行以下操作:
@Override
public User createUser(User user, Set<UserRole> userRoles)
User localUser = userRepository.findByUsername(user.getUsername());
if(localUser != null)
LOG.info("User with username already exist. Nothing will be done. ", user.getUsername());
else
user.getUserRoles().addAll(userRoles);
localUser = userRepository.save(user);
for (UserRole ur : userRoles)
roleRepository.save(ur.getRole());
userRoleRepository.save(ur);
return localUser;
如您所见,我只对调用进行了重新排序 - 首先存储 User
,然后转到 userRoles
以获取此 User
。
【讨论】:
思路是对的。我检查了用户和用户角色的 id 都是空的,所以它变成了先有鸡还是先有蛋的难题。我将 id 传递给了用户角色,它可以工作,但无法在数据库中创建用户角色表以上是关于Spring + Mongodb 与 Null id 问题的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB DBRef 列表在 Spring Boot 中返回 null
使用spring boot MongoTemplate删除mongodb记录会抛出错误:“Second is Null”