JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作

表关系的分析

数据库中多表之间存在着三种关系:


JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第1张图片
表关系

表与表的三种关系:

一对多|多对一

建表原则:在多的一方创建外键指向一的一方的主键

JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第2张图片
一对多

表中的表达

JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第3张图片
表中表达

实体中的表达

JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第4张图片
实体中的表达

orm元数据表达

  • 多对一配置
 
        

        

这里的这个配置表示的是:当前的这个配置对象存在多对一的情况,其中name表示实体中多对一的一的名字,column表示外键的列名 class表示的是多个对一个的一的实体类名

  • 一对多配置
 
        
            
            
            
            
        

这里的这个配置表示的是:当前的这个配置对象存在多对一的情况,其中name表示实体中多个的set集合,key column表示外键的列名 class表示的是一对多的多的实体类名

 /**
     *保存客户以及客户下的联系人
     */
    @Test
    public void fun1() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        Customer customer = new Customer();
        customer.setCust_name("xxx");
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("aaa1");
        LinkMan lm2 = new LinkMan();
        lm2.setLkm_name("aaa2");
        //表达一对多关系 客户下有多个联系人
        customer.getLinkMens().add(lm1);
        customer.getLinkMens().add(lm2);
        //表达多对一 联系人属于哪个客户
        lm1.setCustomer(customer);
        lm2.setCustomer(customer);

        //瞬时状态对象---->持久化状态
        session.save(customer);
        session.save(lm1);
        session.save(lm2);
        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }
/**
     * 为客户添加联系人
     */
    @Test
    public void fun2() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        //获得要操作的客户对象
        Customer customer = session.get(Customer.class, 1l);

        //创建联系人
        LinkMan lm1 = new LinkMan();
        //将联系人添加到客户,将客户设置到联系人中
        customer.getLinkMens().add(lm1);
        lm1.setCustomer(customer);
        //执行保存
        session.save(customer);
        session.save(lm1);
        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }
 /**
     * 从客户中删除某个联系人
     */
    @Test
    public void fun3() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        //获得客户
        Customer c = session.get(Customer.class, 1l);
        LinkMan lm = session.get(LinkMan.class, 3l);
        //获得客户的联系人
        //将要移除的联系人从客户的联系人集合中移除
        c.getLinkMens().remove(lm);
        //清空联系人的客户
        lm.setCustomer(null);
        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }

上面的代码再删除某个联系人时由于数据都是查询出来的,都是出于持久态的对象,所以再事务进行提交时Hibernate会查看数据是否发生变化,发生变化后会将数据更新,所以不需要执行session.save()方法进行保存数据

操作进阶

在上面的操作中,我们在操作保存客户的联系人的时候,我们需要执行多条保存的代码,这样显然很麻烦,我们希望再保存客户的时候,将客户的联系人也一起保存。所以我们需要进行一些别的配置

  • 级联操作
 
        
            
            
            
            
            

        

级联操作应用在一对多的多的时候,也可以实现保存联系人的时候将客户保存

  • linkman.hbm.xml 配置级联操作
 
        

操作代码

/**
     * 级联操作 保存联系人 级联保存客户
     */
    @Test
    public void fun5() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        //创建客户
        Customer customer = new Customer();
        customer.setCust_name("google company");

        //创建联系人
        LinkMan lm = new LinkMan();
        lm.setLkm_name("劈柴哥");
        //为客户添加联系人
        customer.getLinkMens().add(lm);
        //为联系人指定客户
        lm.setCustomer(customer);
        //保存客户----> 只保存联系人 通过级联操作保存客户
        session.saveOrUpdate(lm);

        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }

在平时开发中,建议使用save-update 不建议使用delete 级联删除会删除相关的所有数据

  • 关系维护
    我们查看操作时Hibernate产生的SQL语句时发现了如下的语句
    JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第5张图片
    Hibernate执行的语句.png

    我们发现。在保存时,客户和联系人两房都会维护外键的关系,关系会维护两次,这样冗余了。多余的维护关系语句。显然是客户这一端在维护关系。所以我们需要优化这种情况 这就引入了Hibernate在实体类配置的时候提供的配置 inverse
    inverse是为了提高效率
 
        
            
                class指定是与哪个类型一对多   
            
        

tips:在开发中的删除数据,结合inverse 和cascade 实现不同的数据删除策略。以这个demo为例,一个客户可以由多个联系人。在这种情况下 相当于客户和联系人维持着某种关系。我们在有需求删除客户的时候对联系人的删除有两种。
第一种:删除Customer的时候,将LinkMan的外键置为空,LinkMan数据保留
这种情况下,如果Customer不维护数据的话是无法操作LinkMan的外键的,所以在这种情况下我们需要让Customer inverse配置为false 让customer维护关系,在这种情况下删除Customer的时候会删除LinkMan的关系。
第二种:删除Customer的时候,级联操作将LinkMan的数据删除。
在这种情况下,将Customer inverse设置为true 并且将cascade指定为delete 这样在删除Customer的同时就会删除LinkMan子表中的数据。

多对多关联关系映射操作

建表原则:创建一个中间表,中间表中至少两个字段作为外键分别指向多对多双方的主键

JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第6张图片
多对多

表中关系表达

JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第7张图片
表中表达

实体中的表达

JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作_第8张图片
实体中的表达

orm元数据表达

  • User表配置
  
            
            
            
            
        
  • role表配置
  
        
            
            
        

多对多操作

我们使用案例:保存员工以及角色

在多对多关系中一定要有一方放弃关系的维护,否则会出现主键重复错误
放弃关系维护在配置文件中使用 inverse=“true” 表示放弃操作

  • 配置文件
  
        
            
            
        
  • 实例代码
 //从工厂获得session
        Session session = HibernateUtil.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //操作数据
        //-------------------------------
        //创建两个User
        User user1 = new User();
        User user2 = new User();
        user1.setUser_name("blackman");
        user2.setUser_name("whiteman");

        //创建两个role
        Role role1 = new Role();
        Role role2 = new Role();
        Role role3 = new Role();
        role1.setRole_name("vp");
        role2.setRole_name("cto");
        role3.setRole_name("security");


        //用户表达关系
        user1.getRoles().add(role1);
        user1.getRoles().add(role2);
        user2.getRoles().add(role1);
        user2.getRoles().add(role3);
        //角色表达关系
        role1.getUsers().add(user1);
        role1.getUsers().add(user2);
        role2.getUsers().add(user1);
        role3.getUsers().add(user2);
        //保存到数据库
        session.save(user1);
        session.save(user2);
        session.save(role1);
        session.save(role2);
        session.save(role3);
        //-------------------------------
        //提交事务
        tx.commit();
        //关闭资源
        session.close();

 @Test
    /**
     * 添加角色到某个用户中
     */
    public void addRoleToUser() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();
        //操作
        //------------
        //获得要添加的用户
        User user = session.get(User.class, 1l);
        //创建公关角色
        Role role = new Role();
        role.setRole_name("公关");
        //将角色添加到用户
        user.getRoles().add(role);
        //将角色转换为持久化
        session.save(role);
        //------------
        tx.commit();
        session.close();
    }

/**
* 从指定角色删除
*/
  @Test
    public void delRoleFromUser(){
        //获取session
        Session session = HibernateUtil.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //操作数据
        //-------------
        //获得要删除的数据
        User user = session.get(User.class, 3l);
        //获得要删除的角色数据
        Role role = session.get(Role.class, 7l);
        user.getRoles().remove(role);
        //-------------
        //提交事务
        tx.commit();
        //关闭资源
        session.close();
    }


进阶操作

  • 级联操作
    cascade: 级联操作
    在User.hbm.xml中配置cascade后
        

可以进行级联保存 上面的操作代码不再需要

session.save(role)

一对一

  • 建表原则:
    • 1 唯一外键对应:假设一对一种的任意一方为多,在多的一方创建外键指向一的一方的主键,然后将外键设置为唯一。
    • 2 主键对应:一方的主键作为另一方的主键


      一对一

你可能感兴趣的:(JAVAEE框架学习——Hibernate——一对多|多对多关联关系映射操作)