美文网首页Spring-BootSpringBoot极简教程 · Spring Boot Spring Boot
解决hibernate更新中间表时,会先删除再更新的问题

解决hibernate更新中间表时,会先删除再更新的问题

作者: 就怕是个demo | 来源:发表于2017-11-07 22:06 被阅读851次

    问题:如题,hibernate在更新中间表时,会先删除旧的数据再插入新数据的问题。
    情景:比如现在数据库有一张user表,一张role表,一张user_role中间表


    image.png
    image.png
    image.png
    • 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);
    }
    

    成功!!!

    相关文章

      网友评论

        本文标题:解决hibernate更新中间表时,会先删除再更新的问题

        本文链接:https://www.haomeiwen.com/subject/syjsmxtx.html