• 11.Hibernate一对多关系


    创建JavaBean

    一方: Customer

    private long cust_id;
    private String cust_name;
    private long cust_user_id;
    private long cust_create_id;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_linkman;
    private String cust_phone;
    private String cust_mobile;
    
    //存储联系人的集合,该属性并不会出现在数据库中
    private Set<LinkMan> linkmans = new HashSet<LinkMan>();
    
    //--加上所有的get/set方法 无参构造函数

    多方: LinkMan

    private long lkm_id;
    private String lkm_name;
    private String lkm_gender;
    private String lkm_phone;
    private String lkm_mobile;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_position;
    private String lkm_memo;
    
    //外键对象
    private Customer customer;
    
    //--加上所有的get/set方法 无参构造函数

    配置多方的映射文件

    <!-- 先配置多方 
        name:当前JavaBean中的属性
        class:属性的全路径
        column:外键的字段
    -->
    <many-to-one name="customer" class="com.hibernateday3.domain.Customer" column="lkm_cust_id"/>

    配置一方的映射文件

     <!-- 后配置一方
         set->name:表示集合的名称
     -->
     <set name="linkmans">
         <!-- 外键的字段与路径 -->
         <key column="lkm_cust_id"/>
         <one-to-many class="com.hibernateday3.domain.LinkMan"/>
     </set>

    将映射文件配置到核心文件

    <!-- 映射配置文件 -->
    <mapping resource="com/hibernateday3/domain/Customer.hbm.xml"/>
    <mapping resource="com/hibernateday3/domain/Linkman.hbm.xml"/>    

    测试:

    1.测试双向关联方式

    @Test
        public void m01(){
            Session session = HibernateUtils.openSession();
            Transaction tr = session.beginTransaction();
            
            Customer c1 = new Customer();
            c1.setCust_name("客户1");
            LinkMan l1 = new LinkMan();
            l1.setLkm_name("联系人1");
            LinkMan l2 = new LinkMan();
            l2.setLkm_name("联系人2");
            
            c1.getLinkmans().add(l1);
            c1.getLinkmans().add(l2);
            
            //------保存数据
            //双向关联保存
    session.save(c1); session.save(l1); session.save(l2); //------提交事务释放资源 tr.commit(); session.close(); }

    2.单向的关联,如果不配置级联保存,程序出现异常

    //------保存数据
    //双向关联保存
    
    session.save(c1);
    
    //------提交事务释放资源
    警告:org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.hibernateday3.domain.LinkMan
    

    如果想完成只保存一方的数据,并且把相关联的数据都保存到数据库中,那么需要配置级联!!

    级联保存是具有方向性的

    3.测试级联保存:保存客户,级联联系人

    ---在一方映射文件加入cascade属性

    <set name="linkmans" cascade="save-update">
        <!-- 外键的字段与路径 -->
        <key column="lkm_cust_id"/>
        <one-to-many class="com.hibernateday3.domain.LinkMan" />
    </set>
    //------保存数据
    //双向关联保存
    
    session.save(c1);
    
    //------提交事务释放资源

    运行成功。。

    4.测试级联保存:保存联系人,级联客户

    ---在多方映射文件加入cascade属性

    <many-to-one name="customer" class="com.hibernateday3.domain.Customer" column="lkm_cust_id" cascade="save-update"/>
    //------保存数据
    //双向关联保存
    
    session.save(l1);
    session.save(l2);
    
    //------提交事务释放资源

    运行成功。。

    5.测试级联保存

    
    
    //------保存数据
    //双向关联保存
    l1.setCustomer(c1); c1.getLinkmans().add(l2); session.save(l1);
    //------提交事务释放资源

    运行成功。。

    6.测试:删除一方,一方下有2个联系人

    public void m06(){
        Session session = HibernateUtils.openSession();
        Transaction tr = session.beginTransaction();
        
        //------保存数据
        //双向关联保存
    
        Customer c1 = session.get(Customer.class, 1L);
        session.delete(c1);
        
        //------提交事务释放资源
        tr.commit();
        session.close();
    }

    能够成功 并不会因为一方是多方的外键二不能删除
    Hibernate先让多方删除外键 再删除一方

    7.测试级联删除,删除客户,级联删除客户下的联系人

    在一方映射文件下添加属性

    <set name="linkmans" cascade="save-update,delete">
        <!-- 外键的字段与路径 -->
        <key column="lkm_cust_id"/>
        <one-to-many class="com.hibernateday3.domain.LinkMan" />
    </set>
    //------保存数据
    //双向关联保存
    
    Customer c1 = session.get(Customer.class, 1L);
    session.delete(c1);
    
    //------提交事务释放资源

    删除c1  c1对应的l1,l2都被删除了

    8.删除联系人,级联删除客户

    在多方映射文件下添加属性

        <many-to-one name="customer" class="com.hibernateday3.domain.Customer" column="lkm_cust_id" cascade="save-update,delete"/>
    //------保存数据
    //双向关联保存
    
    LinkMan l1 = session.get(LinkMan.class,1L );
    
    session.delete(l1);
    
    //------提交事务释放资源

    如果一方下的cascadedelete属性依然存在,所有的数据都被删除

    9.解除关系,从一方集合中移除多方数据

    // 先获取到客户
    Customer c1 = session.get(Customer.class, 1L);
    LinkMan l1 = session.get(LinkMan.class, 1L);
    // 解除
    c1.getLinkmans().remove(l1);

    多方的外键被解除设为null

    如果cascade属性为delete-orphan 解除关系 ,多方记录将被删除(孤儿关系)

    1. 取值如下
        * none                      -- 不使用级联
        * save-update               -- 级联保存或更新
        * delete                    -- 级联删除
        * delete-orphan             -- 孤儿删除.(注意:只能应用在一对多关系)
        * all                       -- 除了delete-orphan的所有情况.(包含save-update delete)
        * all-delete-orphan         -- 包含了delete-orphan的所有情况.(包含save-update delete delete-orphan)
    
    2. 孤儿删除(孤子删除),只有在一对多的环境下才有孤儿删除
        * 在一对多的关系中,可以将一的一方认为是父方.将多的一方认为是子方.孤儿删除:在解除了父子关系的时候.将子方记录就直接删除。
        * <many-to-one cascade="delete-orphan" />

    放弃外键维护

    1. 先测试双方都维护外键的时候,会产生多余的SQL语句。
        * 想修改客户和联系人的关系,进行双向关联,双方都会维护外键,会产生多余的SQL语句。
    /**
         * 放弃外键的维护
         * 需求:让c1联系人l1属于c2
         */
        @Test
        public void m11(){
            Session session = HibernateUtils.getCurrentSession();
            Transaction tr = session.beginTransaction();
            
            Customer c2 = session.get(Customer.class,2L);
            LinkMan l1 = session.get(LinkMan.class, 1L);
            
            c2.getLinkmans().add(l1);
            l1.setCustomer(c2);
            
            tr.commit();
        }
    
    
        * 产生的原因:session的一级缓存中的快照机制,会让双方都更新数据库,产生了多余的SQL语句。
    
    2. 如果不想产生多余的SQL语句,那么需要一方来放弃外键的维护!
        * 在<set>标签上配置一个inverse=”true”.true:放弃.false:不放弃.默认值是false
        * <inverse="true">
    <set name="linkmans" inverse="true">
                <!-- 外键的字段与路径 -->
                <key column="lkm_cust_id"/>
                <one-to-many class="com.hibernateday3.domain.LinkMan" />
    </set>
    /**
         * 放弃外键的维护
         * 需求:让c1联系人l1属于c2
         */
        @Test
        public void m11(){
            Session session = HibernateUtils.getCurrentSession();
            Transaction tr = session.beginTransaction();
            
            Customer c2 = session.get(Customer.class,2L);
            LinkMan l1 = session.get(LinkMan.class, 1L);
            
            c2.getLinkmans().add(l1);
            l1.setCustomer(c2);
            
            tr.commit();
        }


    cascade和inverse的区别
    1. cascade用来级联操作(保存、修改和删除)---配置在多方
    2. inverse用来维护外键的  ----配置在一方
  • 相关阅读:
    SQL Server 的事务和锁 图解
    pxc 集群
    Supported_Hardware#4G_LTE_cards_and_modems
    手机性能天梯图
    无线上网卡制式
    python源码学习
    SQLSERVER里面RR隔离级别没有GAP锁
    JAVA EE 博客实例
    REDIS 配制
    SQL SERVER 函数与SQL语法
  • 原文地址:https://www.cnblogs.com/NEWHOM/p/6769993.html
Copyright © 2020-2023  润新知