• hibernate的CRUD操作


    一对多关系映射的crud操作:

    1.单项的保存操作

    /**
    
         * 保存操作
    
         * 正常的保存:创建一个联系人,需要关联客户
    
         */
    
        @Test
    
        public void test1(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           //1.查询一个客户
    
           Customer c1=s.get(Customer.class,1L);
    
           //2.创建一个联系人
    
           LinkMan l=new LinkMan();
    
           l.setLkmName("一对多的联系人");
    
           //3.建立客户联系人的关联关系(让联系人知道他属于哪个客户)
    
           l.setCustomer(c1);
    
           //4.保存联系人
    
           s.save(l);
    
           tx.commit();
    
         }

    2.双向的保存操作:

    /**
    
         * 创建一个客户和一个联系人,创建客户和联系人的双向关系
    
         * 使用符合原则的保存
    
         * 先保存主表的实体,再保存从表的实体
    
         * 此时保存会有问题:
    
         * 保存应该只是两条insert语句,而执行结果是多了一条Update
    
          */
    
    @Test
    
        public void test2(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           //1.创建一个客户
    
           Customer c1=new Customer();//瞬时态对象
    
           c1.setCusname("一对多别的客户2");
    
           //2.创建一个联系人
    
           LinkMan l=new LinkMan();//瞬时态对象
    
           l.setLkmName("一对多的联系人2");
    
           //3.建立客户联系人的关联关系(双向)
    
           l.setCustomer(c1);
    
           c1.getLinkmans().add(l);
    
           //4.保存,要符合原则
    
           s.save(c1);//持久态,会有一级缓存和快照,有OID,和session有关系
    
           s.save(l);//持久态,会有一级缓存和快照,有OID,和session有关系
    
           tx.commit();
    
         }

    注意:在此函数执行的时候,先执行了两条insert语句,然后执行了一条update语句,其原因如下:

     

    是因为Hibernate的快照技术,使得先后执行的语句在快照区的内容不一样,只能在最后commit的时候重新刷新数据库,从而有了一条update语句。

    解决办法:让客户在执行操作的时候,放弃维护关联关系的权利。

         * 配置的方式,在customer的映射配置文件的set标签使用inverse属性

     * inverse:是否放弃维护关联关系的权利,true:是,false:否(默认值)

    <set name="linkmans" table="cust_linkman" inverse="true">
    
            <key column="lkm_cust_id" ></key>
    
            <one-to-many class="LinkMan"></one-to-many></set>

    3.一对多的级联保存

    加入有很多订单,一个一个保存太麻烦,直接用级联保存,就可以一次保存完,而不再用传统的方式一个一个去保存,方法如下:

    /**
    
         * 保存操作,级联操作
    
         * 使用级联保存,配置的方式,
    
         *     使用customer的set标签
    
         *         在上面加入cascade属性
    
         *         cascade:配置级联操作
    
         *         级联保存更新的保存:save-update
    
         *     也可以配置在<one-to-many/>这个标签上
    
         */
    
        @Test
    
        public void test3(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           //1.创建一个客户
    
           Customer c1=new Customer();//瞬时态对象
    
           c1.setCusname("一对多别的客户4");
    
           //2.创建一个联系人
    
           LinkMan l=new LinkMan();//瞬时态对象
    
           l.setLkmName("一对多的联系人4");
    
           //3.建立客户联系人的关联关系(双向)
    
           l.setCustomer(c1);
    
           c1.getLinkmans().add(l);
    
           //4.保存,要符合原则
    
           s.save(c1);//只保存了c1
    
           tx.commit();
    
        }
    
        @Test
    
        public void test4(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           //1.创建一个客户
    
           Customer c1=new Customer();//瞬时态对象
    
           c1.setCusname("一对多别的客户5");
    
           //2.创建一个联系人
    
           LinkMan l=new LinkMan();//瞬时态对象
    
           l.setLkmName("一对多的联系人5");
    
           //3.建立客户联系人的关联关系(双向)
    
           l.setCustomer(c1);
    
           c1.getLinkmans().add(l);
    
           //4.保存,要符合原则
    
           s.save(l);//只保存了l
    
           tx.commit();
    
    }

    注意:在此时的实体类的映射配置中需要加入:

    1,<set/>标签级联保存

    <set name="linkmans" table="cust_linkman" inverse="true" cascade="save-update">
    
                <key column="lkm_cust_id" ></key>
    
                <one-to-many class="LinkMan"></one-to-many>
    
            </set>

    2. <many-to-one name="customer" class="Customer" column="lkm_cust_id" cascade="save-update"></many-to-one>

      用这两种方式都可以实现只需要在代码中保存一个实体,即可保存所有级联实体,只不过配置时候注意要对应配置。  

     4. 更新操作,双向的操作

    /**
    
         * 更新操作:创建一个联系人,查询一个已有客户
    
         * 建立新联系人和已有客户的双向关联关系
    
         * 更新联系人
    
         */
    
        @Test
    
        public void test5(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           //1.查询一个客户
    
           Customer c1=s.get(Customer.class,3L);
    
           //2.创建一个联系人
    
           LinkMan l=new LinkMan();
    
           l.setLkmName("一对多的联系人1");
    
           //3.建立客户联系人的关联关系(双向)
    
           l.setCustomer(c1);
    
           c1.getLinkmans().add(l);
    
           //4.更新客户
    
           s.update(c1);
    
           tx.commit();
    
        }  

    需要注意的是在此时如果set的配置标签里面如果配置了inverse="true"的话,会忽略更新的,这儿需要注意一下,但是cascade必须是save-update,因为在update之前是没有保存那个联系人l,如果不设置这个的话直接报错的。

    5.删除操作

    1.删除的时候如果是从表,则直接删除,若是主表,同时从表的外键可以为null的时候,删除主表的同时直接将其从表中的外键直接置为null

     

     

     

     /**
    
         * 删除操作
    
         *     删除从表就是单表
    
         * 删除主表数据
    
         *     先看从表数据引用
    
         *     有引用:hibernate会吧从表中的外键置位null,然后再删除
    
         *     无引用:直接删
    
         */
    
        @Test
    
        public void test6(){
    
           //此时的外键允许为null
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           //1.查询一个客户
    
           Customer c1=s.get(Customer.class,68L);
    
           //删除ID为68的客户
    
           s.delete(c1);
    
           tx.commit();
    
    }

     

    2.若果从表中要删除某个主表的数据,并且要删除与它级联的从表中的数据,则需要配置级联删除,如下,但是不建议使用该级联删除,是一个很危险的操作

    <set name="linkmans" table="cust_linkman" inverse="false" cascade="save-update,delete">
    
                <key column="lkm_cust_id" ></key>
    
                <one-to-many class="LinkMan"></one-to-many>
    
            </set>

    若从表的外键约束为not null的话,想要在主表中删除某数据,并且此数据在从表中有对应的外键引用,则需要配置主表的额inverse=true,只有配置了这个才可以级联删除,因为只有这样的话,主表才不会维护他的约束,才可以允许级联删除不。

    6.对象导航查询

      一对多的查询操作:OID查询,QBC查询,SQL查询

      hibernate中的最后一种查询方式,对象导航查询

           当两个实体类之间有关联关系时候(可以是任一一种)

           通过调用getXXX方法即可达到实现查询功能(是有hibernate提供的方法)

           eg:customer.getLinkMans()就可以得到当前客户的所有联系人

           通过linkman.getCustomer()就可以得到当前联系人的所属客户

    1. 注意:一对多时候,根据一的一方查询多的一方是,需要使用延迟加载lazy=true(默认配置即可)
     <set name="linkmans" table="cust_linkman" lazy="true">
    
                <key column="lkm_cust_id" ></key>
    
                <one-to-many class="LinkMan"></one-to-many>
    
        </set>
    /**
    
         *查询ID为1的客户下的所属联系人
    
         */
    
        @Test
    
        public void test1(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           Customer c=s.get(Customer.class, 1L);//查询ID为1的客户
    
           /*System.out.println(c);
    
           System.out.println(c.getLinkmans());*/
    
           Set<LinkMan> linkmans=c.getLinkmans();
    
           System.out.println(c);
    
           System.out.println(linkmans);//注意此时是连查询带打印,而不是先查询,在打印
    
           tx.commit();
    
        }
    
    2.多对一时候,根据多的一方查询一的一方时候,不需要使用延迟加载,而是立即加载,需要配置一下,需要找到联系人的<many-to-one>标签上,使用lazy属性,取值有false(立即加载),proxy(看是load方法是延迟加载,还是立即加载)
    
    <class name="LinkMan" table="cust_linkman" lazy="false"><many-to-one name="customer" class="Customer" column="lkm_cust_id" lazy="proxy"></many-to-one>
    
            </class>
    
        /**
    
         *查询ID为5的联系人属于哪个客户
    
         *.多对一时候,根据多的一方查询一的一方时候,不需要使用延迟加载,而是立即加载,
    
         *需要配置一下,需要找到联系人的<many-to-one>标签上,
    
         *使用lazy属性,
    
         *     取值有:
    
         *     false(立即加载),
    
         *     proxy(看是load方法是延迟加载,还是立即加载)
    
         */ @Test
    
        public void test2(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           LinkMan l=s.get(LinkMan.class,5L);
    
           System.out.println(l);
    
           System.out.println(l.getCustomer());//注意此时是连查询带打印,而不是先查询,在打印
    
           tx.commit();
    
        }
    1. 关于load方法的是否延迟加载

    在多的一方配置文件里面的class属性设置lazy=false(这个地方的lazy只负责load方法的加载方式),即立即加载的时候,如果此时设置<many-to-one>里面的属性为lazy=proxy时候,则是根据load方法是否延迟加载来定的,但是<many-to-one>中lazy的级别大于class中配置lazy的级别

     

      /**
    
         * 关于load方法改为立即加载的方式
    
         * 找到查询实体类的映射配置文件,它的class属性上边也有一个lazy属性,是否延迟加载,
    
         * true为延迟加载,false为立即加载
    
         */
    
        @Test
    
        public void test3(){
    
           Session s=HibernateUtils.getCurrentSession();
    
           Transaction tx=s.beginTransaction();
    
           Customer c=s.load(Customer.class, 1L);//查询ID为1的客户
    
           System.out.println(c);
    
           tx.commit();
    
        }

    Class标签的lazy;只能管load的方法是否是延迟加载

    Set标签的lazy:管查询关联的集合对象是否延迟加载

    Many-to-one标签的lazy:只管查询关联的主表实体是否是立即加载

  • 相关阅读:
    TextView走马灯
    Android apk安装时出现“解析软件包错误”
    Android Studio调试手机或者安装APK的时候出现install failed test only
    如何动态改变报表的行高列宽
    如何动态的给报表添加目录
    免费报表工具零代码零基础轻松搞定 web 报表
    脚本中如何做填报数据校验
    脚本填报表的条件查询
    脚本模式下的填报表制作
    交叉填报表的制作
  • 原文地址:https://www.cnblogs.com/wbs19950305/p/8946498.html
Copyright © 2020-2023  润新知