zoukankan      html  css  js  c++  java
  • JavaWeb学习:Hibernate一对多关系简单实列

    1、创建一对多表SQLServer的Sql语句

    CREATE TABLE [dbo].[cst_customer](
        [cust_id] [bigint] IDENTITY(1,1) NOT NULL PRIMARY Key,
        [cust_name] [varchar](32) NOT NULL,
        [cust_source] [varchar](32) NULL,
        [cust_industry] [varchar](32) NULL,
        [cust_level] [varchar](32) NULL,
        [cust_phone] [varchar](64) NULL,
        [cust_mobile] [varchar](16) NULL
    )
    CREATE TABLE [dbo].[cst_linkman](
        [lkm_id] [bigint] IDENTITY(1,1) NOT NULL PRIMARY Key,
        [lkm_name] [varchar](16) NULL,
        [lkm_cust_id] [bigint] NOT NULL FOREIGN KEY([lkm_cust_id]) REFERENCES [cst_customer]([cust_id]) ,
        [lkm_gender] [char](1) NULL,
        [lkm_phone] [varchar](16) NULL,
        [lkm_mobile] [varchar](16) NULL,
        [lkm_email] [varchar](64) NULL,
        [lkm_qq] [varchar](16) NULL,
        [lkm_position] [varchar](16) NULL,
        [lkm_memo] [varchar](512) NULL
    )

    2、引入jar包

     3、配置log4j.properties

    ### direct log messages to stdout ###
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.err
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### direct messages to file mylog.log ###
    log4j.appender.file=org.apache.log4j.FileAppender
    log4j.appender.file.File=c:mylog.log
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### set log levels - for more verbose logging change 'info' to 'debug' ###
    # error warn info debug trace
    log4j.rootLogger= info, stdout

    4、创建实体类

    public class Customer {
        private Long cust_id;
        private String cust_name;
    
        private String cust_source;
        private String cust_industry;
        private String cust_level;
        private String cust_phone;
        private String cust_mobile;
    
        // 通过ORM方式表示:一个客户对应多个联系人。
        // 放置的多的一方的集合。Hibernate默认使用的是Set集合。
        private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    public class 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;
        // 通过ORM方式表示:一个联系人只能属于某一个客户。
        // 放置的是一的一方的对象。
        private Customer customer;

    5、配置持久化类的映射文件

      5.1、Customer.hbm.xml

    <?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>
        <!-- 建立类与表的映射 -->
        <class name="com.hibernate.demo.Customer" table="cst_customer">
            <!-- 建立类中的属性与表中的主键对应 -->
            <id name="cust_id" column="cust_id">
                <generator class="native"></generator>
            </id>
    
            <!-- 建立类中的普通属性与表中的字段对应 -->
            <property name="cust_name" column="cust_name"></property>
            <property name="cust_source" column="cust_source"></property>
            <property name="cust_industry" column="cust_industry"></property>
            <property name="cust_level" column="cust_level"></property>
            <property name="cust_phone" column="cust_phone"></property>
            <property name="cust_mobile" column="cust_mobile"></property>
            <!-- 主要配置一对多的映射:放置的多的一方的集合 -->
            <!-- set标签 :
             * name :多的一方的对象集合的属性名称。 
             * cascade:级联
             * inverse:放弃外键维护权。 -->
            <set name="linkMans" inverse="true" cascade="save-update">
                <!--key标签 
                * column:多的一方的外键的名称。 -->
                <key column="lkm_cust_id" />
                <!-- one-to-many标签
                 * class :多的一方的类的全路径 -->
                <one-to-many class="com.hibernate.demo.LinkMan" />
            </set>
        </class>
    </hibernate-mapping>

      5.2、LinkMan.hbm.xml

    <?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>
        <class table="cst_linkman"    name="com.itheima.hibernate.domain.LinkMan">
            <!-- 建立OID与主键映射 -->
            <id name="lkm_id" column="lkm_id">
                <generator class="native" />
            </id>
            <!-- 建立普通属性与表字段映射 -->
            <property name="lkm_name" />
            <property name="lkm_gender" />
            <property name="lkm_phone" />
            <property name="lkm_mobile" />
            <property name="lkm_email" />
            <property name="lkm_qq" />
            <property name="lkm_position" />
            <property name="lkm_memo" />
            <!-- 主要配置多对一的关系:放置的是一的一方的对象 -->
            <!-- many-to-one标签 
            * name :一的一方的对象的属性名称。 
            * class :一的一方的类的全路径。
            * column :在多的一方的表的外键的名称。 -->
            <many-to-one name="customer" column="lkm_cust_id"
                class="com.hibernate.demo.Customer" />
        </class>
    </hibernate-mapping>

    6、核心配置文件的映射关系

    <mapping resource="com/hibernate/demo/Customer.hbm.xml"/>
    <mapping resource="com/hibernate/demo/LinkMan.hbm.xml"/>

    7、测试代码:

      7.1、一对多两边都保存

    @Test
        public void demo() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //创建两个客户
        Customer customer1=new Customer();
        customer1.setCust_name("张三");
        Customer customer2=new Customer();
        customer2.setCust_name("李四");
        
        //创建三个联系人
        LinkMan linkMan1=new LinkMan();
        linkMan1.setLkm_name("王二");
        LinkMan linkMan2=new LinkMan();
        linkMan2.setLkm_name("王五");
        LinkMan linkMan3=new LinkMan();
        linkMan3.setLkm_name("赵六");
    
        //设置关系
        linkMan1.setCustomer(customer1);
        linkMan2.setCustomer(customer1);
        linkMan3.setCustomer(customer2);
        
        customer1.getLinkMans().add(linkMan1);
        customer1.getLinkMans().add(linkMan2);
        customer2.getLinkMans().add(linkMan3);
        
        // 保存
        session.save(linkMan1);
        session.save(linkMan2);
        session.save(linkMan3);
        session.save(customer1);
        session.save(customer2);
        transaction.commit();
        }

    7.2、一对多关系只保存一边

    @Test
        public void demo1() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //创建两个客户
        Customer customer1=new Customer();
        customer1.setCust_name("张三");
        
        //创建三个联系人
        LinkMan linkMan1=new LinkMan();
        linkMan1.setLkm_name("王二");
    
        //设置关系
        linkMan1.setCustomer(customer1);
        
        customer1.getLinkMans().add(linkMan1);
        
        // 保存
        // 报瞬时对象异常:持久态对象关联了一个瞬时态对象
        //session.save(linkMan1);
        session.save(customer1);
        transaction.commit();
        }

    结果:java.lang.IllegalStateException: org.hibernate.TransientObjectException(报瞬时对象异常)

      7.2.1、解决方案配置级联

        级联:操作一个对象同时操作其关联对象

        级联方向性:

          操作一的一方,同时操作多的一方

          操作多的一方,同时操作一的一方

        7.2.1.1、保存 客户(一) 级联 联系人(多),(客户映射文件Customer.hbm.xml)

        <!-- set标签 :
             * name :多的一方的对象集合的属性名称。 
             * cascade:级联
             * inverse:放弃外键维护权。 -->
            <set name="linkMans" cascade="save-update">
                <!--key标签 
                * column:多的一方的外键的名称。 -->
                <key column="lkm_cust_id" />
                <!-- one-to-many标签
                 * class :多的一方的类的全路径 -->
                <one-to-many class="com.hibernate.demo.LinkMan" />
            </set>
    @Test
        public void demo1() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //创建两个客户
        Customer customer1=new Customer();
        customer1.setCust_name("zhangsan");
        
        //创建三个联系人
        LinkMan linkMan1=new LinkMan();
        linkMan1.setLkm_name("wanger");
    
        //设置关系
        linkMan1.setCustomer(customer1);
        
        customer1.getLinkMans().add(linkMan1);
        
        // 保存
        session.save(customer1);
        transaction.commit();
        }

        7.2.1.2、保存联系人级联客户(操作多同时操作一:配置LinkMan.hbm.xml)

    <!-- 配置多对一的关系:放置的是一的一方的对象 -->
            <!-- many-to-one标签 
            * name :一的一方的对象的属性名称。 
            * class :一的一方的类的全路径。
            * column :在多的一方的表的外键的名称。 -->
            <many-to-one name="customer" cascade="save-update" column="lkm_cust_id"
                class="com.hibernate.demo.Customer" />
    @Test
        public void demo1() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //创建两个客户
        Customer customer1=new Customer();
        customer1.setCust_name("lisi");
        
        //创建三个联系人
        LinkMan linkMan1=new LinkMan();
        linkMan1.setLkm_name("zhaoliu");
    
        //设置关系
        linkMan1.setCustomer(customer1);
        
        customer1.getLinkMans().add(linkMan1);
        
        // 保存
        session.save(linkMan1);
        transaction.commit();
        }

        7.2.2、级联删除

          删除客户级联删除联系人    

    @Test
        public void demo2() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 没有设置级联删除
        Customer customer=session.get(Customer.class, 1l);
        session.delete(customer);
        transaction.commit();
        }

    控制台输出结果:

    Hibernate: 
        update
            cst_linkman 
        set
            lkm_cust_id=null 
        where
            lkm_cust_id=?
    Hibernate: 
        delete 
        from
            cst_customer 
        where
            cust_id=?

          设置级联删除

    <set name="linkMans" cascade="save-update,delete">

    控制台输出结果

    Hibernate: 
        delete 
        from
            cst_linkman 
        where
            lkm_id=?
    Hibernate: 
        delete 
        from
            cst_linkman 
        where
            lkm_id=?
    Hibernate: 
        delete 
        from
            cst_customer 
        where
            cust_id=?

    8、一对多设置了双向关联产生多余的sql语句

        @Test
        public void demo3() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        Customer customer=session.get(Customer.class, 2l);
        LinkMan linkMan=session.get(LinkMan.class, 2l);
        // 双向关联
        linkMan.setCustomer(customer);
        customer.getLinkMans().add(linkMan);
        
        transaction.commit();
        }

    控制台结果:

    Hibernate: 
        update
            cst_linkman 
        set
            lkm_name=?,
            lkm_gender=?,
            lkm_phone=?,
            lkm_mobile=?,
            lkm_email=?,
            lkm_qq=?,
            lkm_position=?,
            lkm_memo=?,
            lkm_cust_id=? 
        where
            lkm_id=?
    Hibernate: 
        update
            cst_linkman 
        set
            lkm_cust_id=? 
        where
            lkm_id=?

    发现cst_linkman中lkm_cust_id被更新两次了

    解决方案一的一方放弃外键维护权:

    一、单向维护

        @Test
        public void demo3() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        Customer customer=session.get(Customer.class, 1l);
        LinkMan linkMan=session.get(LinkMan.class, 2l);
        linkMan.setCustomer(customer);
        //customer.getLinkMans().add(linkMan);
        
        transaction.commit();
        }

    结果:

    Hibernate: 
        update
            cst_linkman 
        set
            lkm_name=?,
            lkm_gender=?,
            lkm_phone=?,
            lkm_mobile=?,
            lkm_email=?,
            lkm_qq=?,
            lkm_position=?,
            lkm_memo=?,
            lkm_cust_id=? 
        where
            lkm_id=?

    二、放弃外键维护权

    <set name="linkMans" cascade="save-update,delete" inverse="true">
        @Test
        public void demo3() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        Customer customer=session.get(Customer.class, 1l);
        LinkMan linkMan=session.get(LinkMan.class, 2l);
        // 双向关联
        linkMan.setCustomer(customer);
        customer.getLinkMans().add(linkMan);
        
        transaction.commit();
        }

    控制台结果:

    Hibernate: 
        update
            cst_linkman 
        set
            lkm_name=?,
            lkm_gender=?,
            lkm_phone=?,
            lkm_mobile=?,
            lkm_email=?,
            lkm_qq=?,
            lkm_position=?,
            lkm_memo=?,
            lkm_cust_id=? 
        where
            lkm_id=?

    9、cascade和inverse的区别

    <set name="linkMans" cascade="save-update,delete" inverse="true">
    @Test
        public void demo4() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        Customer customer=new Customer();
        customer.setCust_name("libing");
        
        LinkMan linkMan=new LinkMan();
        linkMan.setLkm_name("fenjie");
        
        customer.getLinkMans().add(linkMan);
        //cascade和inverse区别
        session.save(customer);
        transaction.commit();
        }

    cascade:作用于关联数据

    inverse:作用于关联数据的外键

  • 相关阅读:
    python sys.path.append
    python中的map()函数
    python中的map、filter、reduce函数
    上传文件2.0--drp203
    The import org.apache.commons.fileupload cannot be resolved
    让我会好好学习一阵子的东西
    【JSP】--Error错误页设置,声明式异常--188 drp
    【JSP】--重定向,转发--186 drp
    【JSP】--路径问题--如何去掉../,直接写绝对路径
    主备切换,双机热备,负载均衡,nginx
  • 原文地址:https://www.cnblogs.com/WarBlog/p/13953728.html
Copyright © 2011-2022 走看看