欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JPA(六)多对多

程序员文章站 2022-03-02 15:28:30
...

1.多对多实体类配置

@Entity
@Table(name = "role")
public class Role {

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

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

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "rid",referencedColumnName="role_id")}, 
                            inverseJoinColumns = {@JoinColumn(name = "uid",referencedColumnName="user_id")})
    private Set<Users> userList = new HashSet<>();
}   
@Entity
@Table(name = "users")
public class Users {

    @Id
    @Column(name = "user_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;
    @Column(name = "user_name")
    private String userName;
    @Column(name = "user_address")
    private String address;
    @Column(name = "user_gender")
    private String gender;

    @ManyToMany(cascade=CascadeType.ALL,mappedBy="userList")
    private Set<Role> roles = new HashSet<>(0);
}

2、注解说明

- @ManyToMany
作用:
  用于映射多对多关系
属性:
  cascade:配置级联操作。
  fetch:配置是否采用延迟加载。
  targetEntity:配置目标的实体类。映射多对多的时候不用写。

  • @JoinTable
    作用:
    针对中间表的配置
    属性:
      nam:配置中间表的名称
      joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段
      inverseJoinColumn:中间表的外键字段关联对方表的主键字段
    - @JoinColumn
    作用:
      用于定义主键字段和外键字段的对应关系。
    属性:
      name:指定外键字段的名称
      referencedColumnName:指定引用主表的主键字段名称
      unique:是否唯一。默认值不唯一
      nullable:是否允许为空。默认值允许。
      insertable:是否允许插入。默认值允许。
      updatable:是否允许更新。默认值允许。
      columnDefinition:列的定义信息。

3测试

3.1、保存

    /**
     * 
     * 1、保存一个实体
     */
    @Test
    public void testAdd() {
        // 定义对象
        Role role1 = new Role();
        Role role2 = new Role();
        Users users1 = new Users();
        Users users2 = new Users();


        role1.setRoleName("角色1");
        role1.getUserList().add(users1);
        role1.getUserList().add(users2);

        role2.setRoleName("角色2");
        role2.getUserList().add(users2);

        users1.setAddress("北京");
        users1.setGender("男");
        users1.setUserName("张三");
        users1.getRoles().add(role1);

        users2.setAddress("上海");
        users2.setGender("女");
        users2.setUserName("赵四");
        users2.getRoles().add(role1);
        users2.getRoles().add(role2);

        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            // 获取实体管理对象
            em = JpaUtil.getEntityManager();
            // 获取事务对象
            tx = em.getTransaction();
            // 开启事务
            tx.begin();
            // 执行操作

            em.persist(role1);

            // 提交事务
            tx.commit();
        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的 2
个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即
可,推荐在被动的一方放弃,配置如下:
@ManyToMany(mappedBy="roles")
private Set<SysUser> users = new HashSet<SysUser>(0);

3.2删除

     /**
        * 删除操作
        * 删除从表数据:可以随时任意删除。
        * 删除主表数据:
        * 有从表数据引用
        * 1、不能删除
        * 2、如果还想删除,使用级联删除
        * 没有从表数据引用:随便删
        *
        * 在实际开发中,级联删除请慎用!(在一对多的情况下)
        */
    @Test
    public void testRemove() {
        // 定义对象
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            // 获取实体管理对象
            em = JpaUtil.getEntityManager();
            // 获取事务对象
            tx = em.getTransaction();
            // 开启事务
            tx.begin();
            // 执行操作
            Users u = em.find(Users.class, 2L);

            em.remove(u);
            // 提交事务
            tx.commit();

        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
级联删除的配置:
@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.AL
L) //用 CascadeType.REMOVE 也可以
private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);