问题:如题,hibernate在更新中间表时,会先删除旧的数据再插入新数据的问题。
情景:比如现在数据库有一张user表,一张role表,一张user_role中间表
- User实体类
@Data
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = -6325275400468409210L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Expose
private long id;
@JsonIgnore
@Column
private String uid;
@Column
@Expose
private String phone;
@Column
@Expose
private String email;
@Column
@JsonIgnore
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@Expose
private List<Role> roles;
- 测试:当user有角色“ROLE_USER_NORMAL”的前提下,想给user在添加一个角色“ROLE_USER_ADMIN”,这是会出现user_role表中id为1的数据被删除,然后添加了两条新数据,id分别为2和3,其中id为2的数据和被删除的id为1的数据相同。
@Test
public void testAddRoleForUser() throws Exception {
User user = userRepository.findByPhone("183xxxxxxxx");
Role role = roleRepository.findByName("ROLE_USER_ADMIN");
user.getRoles().add(role);
userRepository.save(user);
}
- 解决:
1、将List<Role> roles改为Set<Role> roles。
2、重写主表实体类的equals()和hasCode()方法。
@Data
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = -6325275400468409210L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Expose
private long id;
@JsonIgnore
@Column
private String uid;
@Column
@Expose
private String phone;
@Column
@Expose
private String email;
@Column
@JsonIgnore
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@Expose
private Set<Role> roles;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
return false;
}
@Override
public int hashCode() {
int result = 20;
result = (int) (result * 31 + id);
result = result * 31 + uid.hashCode();
result = result * 31 + phone.hashCode();
result = result * 31 + email.hashCode();
result = result * 31 + password.hashCode();
return result;
}
此时再测试时,将不会删除id为1的数据,而是直接添加id为2的新数据。
再来测试一下从两个角色中删除“ROLE_USER_ADMIN”这个角色。
@Test
public void testDeleteRoleFromUser() throws Exception {
User user = userRepository.findByPhone("18349178884");
Set<Role> roles = user.getRoles();
Iterator<Role> it = roles.iterator();
//roles.removeIf(role1 -> role1.getName().equals("ROLE_USER_ADMIN")); 等价于下面的while循环
while (it.hasNext()) {
Role role = it.next();
if (role.getName().equals("ROLE_USER_ADMIN")) {
it.remove();
}
}
log.info("roles: {}", roles);
userRepository.save(user);
}
成功!!!