Spring 单向一对多关系的启动问题
Spring boot problem with Unidirectional OneToMany Relationship
所以我希望用户有很多笔记,这意味着用户和笔记之间的关系类型应该是OneToMany(意思是一个用户有很多笔记)。所以我的应用程序中有一个非常奇怪的错误。当创建注释并将其添加到数据库时,然后我也将它保存在用户中,它第一次工作正常,但是在第二次尝试时我收到错误“无法添加或更新子行:外键约束失败” .当我将一个注释添加到数据库时它可以工作但是当我添加另一个注释时它会给出同样的错误。我已经修复了数据库中设置 foreign_key_checks=0 的错误并且它可以工作,但是在我的应用程序中它不起作用。
这是我针对不同 类:
的代码
备注:
@Entity
@Table(name = "notes")
@Getter
@Setter
@ToString
public class Note {
@Id
@Column(name = "note_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String description;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate = new Date(System.currentTimeMillis());
}
用户:
@Entity
@Table(name = "users")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
@Column(name = "user_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
private String nickname;
private Integer age;
@Column(nullable = false)
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "users_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "note_id", referencedColumnName = "user_id")
private Set<Note> notes = new HashSet<>();
public void addRole(Role role){
this.roles.add(role);
}
public void addNote(Note note){this.notes.add(note);}
public Set<Note> getNotes(){
return this.notes;
}
}
备注服务:
@Service
public class NoteService {
@Autowired
private NoteRepository noteRepository;
@Autowired
private UserService userService;
public List<Note> getAllNote(){
return noteRepository.findAll();
}
public Note getNote(Long id) throws noteNotFoundException {
Optional<Note> result = noteRepository.findById(id);
if(result.isPresent()){
return result.get();
}
//chveni sheqmnili exeptioni
throw new noteNotFoundException("Could not find any note with given ID: " + id);
}
public void save(Note note) {
noteRepository.save(note);
}
public void deleteNoteById(Long id) throws noteNotFoundException {
if(getNote(id)==null){
throw new noteNotFoundException("Could not find any note with given ID: " + id);
}
noteRepository.deleteById(id);
}
}
用户服务:
@Service
public class UserService {
private final Integer USER_ROLE_ID = 1;
private final Long ADMIN_ID = 3L;
@Autowired
private UserRepository repository;
@Autowired
private RoleService roleService;
public List<User> getAllUser(){
return (List<User>) repository.findAll();
}
public List<User> getAllUsersWithoutAdmin(){
List<User> allUsers = repository.findAll();
User admin = repository.getById(ADMIN_ID);
allUsers.remove(admin);
return allUsers;
};
public void save(User u) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode(u.getPassword());
u.setPassword(encodedPassword);
try {
u.addRole(roleService.getRole(USER_ROLE_ID));
} catch (userNotFoundException e) {
e.printStackTrace();
}
repository.save(u);
}
public void saveNoteToUser(Note note){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = repository.findByEmail(authentication.getName());
user.addNote(note);
repository.save(user);
}
public Set<Note> getAllNotes(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = repository.findByEmail(authentication.getName());
return user.getNotes();
}
public User getUser(Long id) throws userNotFoundException {
Optional<User> result = repository.findById(id);
if(result.isPresent()){
return result.get();
}
//chveni sheqmnili exeptioni
throw new userNotFoundException("Could not find any user with given ID: " + id);
}
public void deleteUserById(Long id) throws userNotFoundException {
//eseigi jer itvli tu 0 ia an null errors abruen
//tu useri arsebobs mere adeleteb
Long count = repository.countById(id);
if(count == null || count==0){
throw new userNotFoundException("Could not find any user with given ID: " + id);
}
repository.deleteById(id);
}
}
最后映射:
@PostMapping("/notes/save")
public String saveNote(Note note, RedirectAttributes ra){
noteService.save(note);
userService.saveNoteToUser(note);
//ra atributi ari roca redirect moxdeba mere ro dawers messijs anu redirectis mere xdeba
ra.addFlashAttribute("message", "The note has been added successfully.");
return "redirect:/notes";
}
如您所见,在映射中,首先我试图在数据库中保存一条注释,然后我想将该注释添加到用户本身。然而如上所述,它只工作一次,但是当我想添加另一个注释时,我得到这个错误:
java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`myfirstappdb`.`notes`, CONSTRAINT `FKb7tumg0c2p1wt2ifjag2gv998` FOREIGN KEY (`note_id`) REFERENCES `users` (`user_id`))
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1098) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1046) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1371) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1031) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na]
根据 Hibernate 文档,当您的实体模式中有单向关系并且您只有 @OneToMany
的一侧时,您不能使用注释 @JoinColumn
.
When using a unidirectional @OneToMany association, Hibernate resorts
to using a link table between the two joining entities.
您必须删除 @JoinColumn
以便 hibernate 遵循创建中间连接的默认过程 table 然后它将能够继续。
所以我希望用户有很多笔记,这意味着用户和笔记之间的关系类型应该是OneToMany(意思是一个用户有很多笔记)。所以我的应用程序中有一个非常奇怪的错误。当创建注释并将其添加到数据库时,然后我也将它保存在用户中,它第一次工作正常,但是在第二次尝试时我收到错误“无法添加或更新子行:外键约束失败” .当我将一个注释添加到数据库时它可以工作但是当我添加另一个注释时它会给出同样的错误。我已经修复了数据库中设置 foreign_key_checks=0 的错误并且它可以工作,但是在我的应用程序中它不起作用。
这是我针对不同 类:
的代码备注:
@Entity
@Table(name = "notes")
@Getter
@Setter
@ToString
public class Note {
@Id
@Column(name = "note_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String description;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate = new Date(System.currentTimeMillis());
}
用户:
@Entity
@Table(name = "users")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
@Column(name = "user_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
private String nickname;
private Integer age;
@Column(nullable = false)
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "users_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "note_id", referencedColumnName = "user_id")
private Set<Note> notes = new HashSet<>();
public void addRole(Role role){
this.roles.add(role);
}
public void addNote(Note note){this.notes.add(note);}
public Set<Note> getNotes(){
return this.notes;
}
}
备注服务:
@Service
public class NoteService {
@Autowired
private NoteRepository noteRepository;
@Autowired
private UserService userService;
public List<Note> getAllNote(){
return noteRepository.findAll();
}
public Note getNote(Long id) throws noteNotFoundException {
Optional<Note> result = noteRepository.findById(id);
if(result.isPresent()){
return result.get();
}
//chveni sheqmnili exeptioni
throw new noteNotFoundException("Could not find any note with given ID: " + id);
}
public void save(Note note) {
noteRepository.save(note);
}
public void deleteNoteById(Long id) throws noteNotFoundException {
if(getNote(id)==null){
throw new noteNotFoundException("Could not find any note with given ID: " + id);
}
noteRepository.deleteById(id);
}
}
用户服务:
@Service
public class UserService {
private final Integer USER_ROLE_ID = 1;
private final Long ADMIN_ID = 3L;
@Autowired
private UserRepository repository;
@Autowired
private RoleService roleService;
public List<User> getAllUser(){
return (List<User>) repository.findAll();
}
public List<User> getAllUsersWithoutAdmin(){
List<User> allUsers = repository.findAll();
User admin = repository.getById(ADMIN_ID);
allUsers.remove(admin);
return allUsers;
};
public void save(User u) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode(u.getPassword());
u.setPassword(encodedPassword);
try {
u.addRole(roleService.getRole(USER_ROLE_ID));
} catch (userNotFoundException e) {
e.printStackTrace();
}
repository.save(u);
}
public void saveNoteToUser(Note note){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = repository.findByEmail(authentication.getName());
user.addNote(note);
repository.save(user);
}
public Set<Note> getAllNotes(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = repository.findByEmail(authentication.getName());
return user.getNotes();
}
public User getUser(Long id) throws userNotFoundException {
Optional<User> result = repository.findById(id);
if(result.isPresent()){
return result.get();
}
//chveni sheqmnili exeptioni
throw new userNotFoundException("Could not find any user with given ID: " + id);
}
public void deleteUserById(Long id) throws userNotFoundException {
//eseigi jer itvli tu 0 ia an null errors abruen
//tu useri arsebobs mere adeleteb
Long count = repository.countById(id);
if(count == null || count==0){
throw new userNotFoundException("Could not find any user with given ID: " + id);
}
repository.deleteById(id);
}
}
最后映射:
@PostMapping("/notes/save")
public String saveNote(Note note, RedirectAttributes ra){
noteService.save(note);
userService.saveNoteToUser(note);
//ra atributi ari roca redirect moxdeba mere ro dawers messijs anu redirectis mere xdeba
ra.addFlashAttribute("message", "The note has been added successfully.");
return "redirect:/notes";
}
如您所见,在映射中,首先我试图在数据库中保存一条注释,然后我想将该注释添加到用户本身。然而如上所述,它只工作一次,但是当我想添加另一个注释时,我得到这个错误:
java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`myfirstappdb`.`notes`, CONSTRAINT `FKb7tumg0c2p1wt2ifjag2gv998` FOREIGN KEY (`note_id`) REFERENCES `users` (`user_id`))
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1098) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1046) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1371) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1031) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na]
根据 Hibernate 文档,当您的实体模式中有单向关系并且您只有 @OneToMany
的一侧时,您不能使用注释 @JoinColumn
.
When using a unidirectional @OneToMany association, Hibernate resorts to using a link table between the two joining entities.
您必须删除 @JoinColumn
以便 hibernate 遵循创建中间连接的默认过程 table 然后它将能够继续。