SpringDataJpa(六) 多表操作-多对多

SpringDataJpa(六) 多表操作-多对多

1.实例分析 用户:角色

用户:角色===> n : n
一个用户可以有多个角色,一个角色可以赋予多个用户
eg: 用户:李四 既是教师又是java工程师,张三也是教师

  • 李四有教师,java工程师两个角色
  • 教师这个角色同时赋予了,张三和李四

用户和角色是多对多的关系

2.表关系建立

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AbfkD1K6-1582204680891)(./1582202974765.png)]

3.实体类与数据库表关系映射

用户表: sys_user
角色表: sys_role
中间表:sys_user_role

User.java

用户实体类

/**
 *  用户实体类
 */
Entity
Table(name = "sys_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long userId;
    @Column(name = "user_name")
    private String userName;
    @Column(name = "age")
    private Integer age;

    /**
     *  配置多对多映射
     *     配置中间表
     */
    @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",  //中间表名称
               // 当前对象在中间表中的外键
               joinColumns = {@JoinColumn(name = "sys_user_id", referencedColumnName = "user_id")},
               // 对方对象在中间表中的外键
               inverseJoinColumns = {@JoinColumn(name = "sys_role_id", referencedColumnName = "role_id")}

    )
    private Set<Role> roles = new HashSet<Role>();
}
Role.java 角色实体类
/**
 * 角色实体类
 */
@Entity
@Table(name = "sys_role")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Long roleId;

    @Column(name = "role_name")
    private String roleName;

    /**
     *  创建外键关联
     */
  /*  @ManyToMany(targetEntity = User.class)
    @JoinTable(name = "sys_user_role",  //中间表名称
            // 当前对象在中间表中的外键
            joinColumns = {@JoinColumn(name = "sys_role_id", referencedColumnName = "role_id")},
            // 对方对象在中间表中的外键
            inverseJoinColumns = {@JoinColumn(name = "sys_user_id", referencedColumnName = "user_id")}

    )*/
    @ManyToMany(mappedBy = "roles")  //放弃外键维护
    private Set<User> users = new HashSet<User>();
}
UserDao 用户持久层
/**
 * 用户持久层
 */
public interface UserDao extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}
RoleDao 角色持久层
/**
 * 角色持久层
 */
public interface RoleDao extends JpaRepository<Role, Long>, JpaSpecificationExecutor<Role> {
}

4.映射注解说明

@ManyToMany

  • 作用:用于映射多对多关系
  • 属性:
    • mapperBy:放弃外键维护权力,由关联表1维护外键
    • cascade:配置级联操作。
    • fetch:配置是否采用延迟加载。
    • targetEntity:配置目标的实体类

@JoinTable

  • 作用:中间表配置
  • 属性:
  • name:中间表名称
  • joinColumns:
    • name:当前实体类在中间表中对应的外键字段
    • referenceColumnName:当前实体类与数据库表对应的主键
  • inverserJoinColumn:
    • name:对方实体类在中间表中对应的外键字段
    • referenceColumnName:对方实体类与数据库表对应的主键

@JoinColumn

  • 作用:用于定义主键字段和外键字段的对应关系。
  • 属性:
    • name:指定外键字段的名称
    • referencedColumnName:指定引用主表的主键字段名称
    • unique:是否唯一。默认值不唯一
    • nullable:是否允许为空。默认值允许
    • insertable:是否允许插入。默认值允许。
    • updatable:是否允许更新。默认值允许
    • columnDefinition:列的定义信息。

5.测试

保存
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:applicationContext.xml")
public class ManyToManyTest {

    @Autowired
    private UserDao userDao;

    @Autowired
    private RoleDao roleDao;

    @Test
    @Transactional
    @Rollback(false)
    public void test_save(){

        User user = new User();
        user.setUserName("张三");

        Role role = new Role();
        role.setRoleName("ADMIN");

        //建立联系
        user.getRoles().add(role);
        role.getUsers().add(user);

        userDao.save(user);

    }
 }

问题:多对多保存时,如果设置双向关系,意味着双方都有外键维护权,保存时都会向中间表插入数据,会造成同一条记录插入两次,主键重复,会报错。
解决:让被动的一方放弃外键维护权力
Role.java

 @ManyToMany(mappedBy = "roles")
 private Set<User> users = new HashSet<User>();
删除
cascade:配置级联操作
  • CascadeType.MERGE 级联更新
  • CascadeType.PERSIST 级联保存
  • CascadeType.REFRESH 级联刷新
  • CascadeType.REMOVE 级联删除
  • CascadeType.ALL 级联所有操作

User.java

/***
* CascadeType.ALL  级联所有操作
*/
@ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
private Set<Role> roles = new HashSet<Role>();
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:applicationContext.xml")
public class ManyToManyTest {
    /**
     *  级联删除--- 只能单项关系级联
     *     删除用户级联删除角色
     * 	双向级联删除根本不能配置
	 * 禁用
	 *	如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
     */
    @Test
    public void test_del(){
        User user = userDao.findOne(1l);
        userDao.delete(user);
    }
}
发布了47 篇原创文章 · 获赞 7 · 访问量 2330

猜你喜欢

转载自blog.csdn.net/qq_43616898/article/details/104418355