• Hibernate入门(八)级联保存或更新(含问题在末尾,求大佬指点..)


    级联保存或更新CASCADE

    级联保存或更新:

      作用就是:保存一方的数据的时候,会把关联的对象也同时保存。

    级联保存或更新的配置:

        属性名:cascade

            属性值:

                1.none:所有情况下均不进行关联操作。(默认值)

                2.save-update:在执行save/update/saveOrUpdate时进行关联操作

                3.delete:在执行delete时进行关联操作

                4.all-delete-orphan:当一个节点在对象图中成为孤儿节点时,删除该节点

                5.all:所有情况下均进行关联操作,即save-update和delete(但是不推荐,避免删除后级联删除最后导致莫名其妙少了很多数据)

    先贴上一段代码:

        这段代码是上一章的代码,作用是创建新用户并且创建两个订单添加到该客户中。

        新创建的对象都是瞬时状态,我们保存到数据库需要将对象进行持久化操作。

        这里发现,最后持久化对象用了三行代码。

         session.save(cst); session.save(od); session.save(od1);

        又保存客户,又保存两个订单,感觉代码有点多。但是不执行后两个行代码又不行,瞬时状态的怎么可以!

        所以我们就得设置级联操作了,这样就可以保存某一方的同时,自动保存或更新级联的对象。

    /**
         * 创建新用户并且创建两个订单添加到该客户中
         */
        @Test
        public void fun1(){
            Session session = HibernateUtils.getSession();
            session.getTransaction().begin();
            
            
            try {
                //新建用户  瞬时状态
                Customer cst = new Customer();
                cst.setCust_id(1);
                cst.setCust_name("台用胜");
                cst.setCust_gender("男");
                cst.setCust_age(24);
                cst.setCust_phone("18736549531");
                
                //新建订单 瞬时状态
                Order od = new Order();
                od.setOrder_id(UUID.randomUUID().toString());
                od.setDetail_id(UUID.randomUUID().toString());
                
                Order od1 = new Order();
                od1.setOrder_id(UUID.randomUUID().toString());
                od1.setDetail_id(UUID.randomUUID().toString());
                
                //表达客户和订单的关系
                cst.getOds().add(od);
                cst.getOds().add(od1);
                //表达订单和客户的关系
                od.setCst(cst);
                od1.setCst(cst);
                //持久化用户和订单
                session.save(cst);
                session.save(od);
                session.save(od1);
            } catch (Exception e) {
                session.getTransaction().rollback();
                e.printStackTrace();
            }
            
            session.getTransaction().commit();
        }

    级联保存或更新的操作:

      这里有客户对订单的关系,上述中,给客户添加订单需要三行代码。

      这三行代码中, 如果我们认为客户方是“主控方”那么后面的两行代码我们就可以省略,如果我们认为订单方是“主控方”那么第一行的代码就可以省略。具体看代码

      那我就举一个例子,选择客户方是“主控方”,

      1.配置Customer.hbm.xml(在配置的时候添加cascade="save-update")

    <?xml version = "1.0" encoding = "UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="deep.domain">
        <class name="Customer" table="customera">
            <id name="cust_id" column = "cust_id">
                <generator class="native"></generator>
            </id>
            
            <property name="cust_name" column = "cust_name"></property>
            <property name="cust_gender" column = "cust_gender"></property>
            <property name="cust_age" column = "cust_age"></property>
            <property name="cust_phone" column = "cust_phone"></property>
            
            <!-- 配置一对多属性 -->
            <set name="ods" cascade="save-update">
                <key column="cust_order_id" ></key>
                <one-to-many class="Order"/>
            </set>
            
        </class>
        
    </hibernate-mapping>

    2.随后将上面粘贴的java代码进行修改(我们会发现,少了session.save(od)和session.save(od1)),但是效果是一样的

    /**
         * 级联保存或更新
         * 创建新用户并且创建两个订单添加到该客户中
         */
        @Test
        public void fun2(){
            Session session = HibernateUtils.getSession();
            session.getTransaction().begin();
        
            try {
                //新建用户  瞬时状态
                Customer cst = new Customer();
                cst.setCust_id(1);
                cst.setCust_name("台用胜");
                cst.setCust_gender("男");
                cst.setCust_age(24);
                cst.setCust_phone("18736549531");
                
                //新建订单 瞬时状态
                Order od = new Order();
                od.setDetail_id(UUID.randomUUID().toString());
                
                Order od1 = new Order();
                od1.setDetail_id(UUID.randomUUID().toString());
                
                //表达客户和订单的关系
                cst.getOds().add(od);
                cst.getOds().add(od1);
                //表达订单和客户的关系
                od.setCst(cst);
                od1.setCst(cst);
                
                //持久化用户和订单
                session.save(cst);
            } catch (Exception e) {
                session.getTransaction().rollback();
                e.printStackTrace();
            }
            
            session.getTransaction().commit();
        }

    同样,如果我们认为订单方是“主控方”,那么就只要这样配置

    <!-- 配置多对一属性 -->
            <many-to-one name="cst" class="Customer" column="cust_order_id" cascade="save-update" />

    随后的java代码是:(获取主键值为 6的客户,并新建两个订单添加到该客户中)

    /**
         * 级联保存或更新
         * 获取用户并且创建两个订单添加到该客户中
         */
        @Test
        public void fun3(){
            Session session = HibernateUtils.getSession();
            session.getTransaction().begin();
        
            try {
                //获取主键值为6的客户  瞬时状态
                Customer cst = session.get(Customer.class, 6);
                
                //新建订单 瞬时状态
                Order od = new Order();
                od.setDetail_id(UUID.randomUUID().toString());
                
                Order od1 = new Order();
                od1.setDetail_id(UUID.randomUUID().toString());
                
                //表达客户和订单的关系
                cst.getOds().add(od);
                cst.getOds().add(od1);
                //表达订单和客户的关系
                od.setCst(cst);
                od1.setCst(cst);
                
                //持久化用户和订单
                session.save(od);
                session.save(od1);
            } catch (Exception e) {
                session.getTransaction().rollback();
                e.printStackTrace();
            }
            
            session.getTransaction().commit();
        }

    刚刚上面的是两种单一方向,也可以认为订单方和客户方都是“主控方”,方法自然很简单,就是在两边都加上cascade="save-update"啦~

    到这里cascade概念基本可以了,我也算是有点理解了吧,这样确实方便很多,少了代码量,也比较人性化。

    问题:我的订单表中的主键这是的是uuid,在配置文件中设置了主键自增策略是uuid,在创建新订单的时候,我有一个订单.setId的动作,并且手动生成了uuid。 在我没有级联操作的时候,能够正常添加订单,但是级联操作后就会报错,java代码和报错代码如下(我认为客户方是“主控方”)

    错误明细:

     十一月 18, 2018 4:31:07 下午 org.hibernate.internal.SessionImpl$5 mapManagedFlushFailure
    ERROR: HHH000346: Error during managed flush [Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1]

    百度查了也没搞懂是怎么回事,想了有一会儿,然后报错,看到错误来源sql语句update的第一个参数,我就看到了我java中,然后猜测是主键策略方面的问题,我就尝试把那一行代码删除,发现可以运行,但是不知道为什么。如果有大佬知道希望能指点一二。。谢谢啦~

  • 相关阅读:
    Mycat的server.xml配置
    Docker构建Mycat(单节点)
    Mycat相关概念解读
    Mycat简介及适用场景
    SpringBoot整合WebService
    SpringBoot事务简单操作及手动回滚
    对事务及其注解@Transactional的解读
    git将某分支的某次提交合并到另一分支
    SpringBoot快速支持国际化i18n
    SpringBoot多数据源自动切换
  • 原文地址:https://www.cnblogs.com/deepSleeping/p/9978296.html
Copyright © 2020-2023  润新知