zoukankan      html  css  js  c++  java
  • JPA(六):映射关联关系------映射单向一对多的关联关系

    映射单向一对多的关联关系

    新建项目项目请参考《JPA(二):HellWord工程》,基于上一章讲解的《JPA(五):映射关联关系------映射单向多对一的关联关系》中的例子进行修改(需要清空数据中的表,因为本例子还是使用customer,order表来测试,但是关联关系发生了变化):

    Customer.java

    package com.dx.jpa.singlemanytoone;
    
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    import javax.persistence.Transient;
    
    @Entity
    @Table(name = "jpa_customer")
    public class Customer {
        private Integer id;
        private String fullName;
        private Integer age;
        private Date birth;
        private Date createDate;
        private Set<Order> orders = new HashSet<>();
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        @Column(name = "FULL_NAME", length = 64, nullable = false)
        public String getFullName() {
            return fullName;
        }
    
        public void setFullName(String fullName) {
            this.fullName = fullName;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Temporal(TemporalType.DATE)
        public Date getBirth() {
            return birth;
        }
    
        public void setBirth(Date birth) {
            this.birth = birth;
        }
    
        @Temporal(TemporalType.TIMESTAMP)
        public Date getCreateDate() {
            return createDate;
        }
    
        public void setCreateDate(Date createDate) {
            this.createDate = createDate;
        }
    
        // 映射一对多的关联关系
        // @JoinColumn 用来映射一对多的关联关系
        // @OneToMany 用来映射外键列
        @JoinColumn(name = "CUSTOMER_ID")
        @OneToMany()
        public Set<Order> getOrders() {
            return orders;
        }
    
        public void setOrders(Set<Order> orders) {
            this.orders = orders;
        }
    
        // 帮助方法,不希望保存到数据库,但是需要动态获取Customer对象的属性。
        @Transient
        public String getCustomerInfo() {
            return "username:" + fullName + ",age:" + age;
        }
    }
    View Code

    注意:这里在Customer.java中添加了一对多的注解@OneToMany:

        // 映射一对多的关联关系
        // @JoinColumn 用来映射一对多的关联关系
        // @OneToMany 用来映射外键列
        @JoinColumn(name = "CUSTOMER_ID")
        @OneToMany()
        public Set<Order> getOrders() {
            return orders;
        }

    Order.java

    package com.dx.jpa.singlemanytoone;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @Table(name = "jpa_order")
    public class Order {
        private Integer id;
        private String name;
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    View Code

    初始化JPA项目时,创建表语句如下:

    Hibernate: 
        
        create table hibernate_sequence (
           next_val bigint
        ) engine=InnoDB
    Hibernate: 
        
        insert into hibernate_sequence values ( 1 )
    Hibernate: 
        
        insert into hibernate_sequence values ( 1 )
    Hibernate: 
        
        create table jpa_customer (
           id integer not null,
            age integer,
            birth date,
            createDate datetime,
            FULL_NAME varchar(64) not null,
            primary key (id)
        ) engine=InnoDB
    Hibernate: 
        
        create table jpa_order (
           id integer not null,
            name varchar(255),
            CUSTOMER_ID integer,
            primary key (id)
        ) engine=InnoDB
    Hibernate: 
        
        alter table jpa_order 
           add constraint FK7glkngwj74nr8h2amofkp1fjd 
           foreign key (CUSTOMER_ID) 
           references jpa_customer (id)
    View Code

    persistence.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0"
        xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
        <persistence-unit name="Jpa-helloword"
            transaction-type="RESOURCE_LOCAL">
            <!-- 配置使用什么 ORM 产品来作为 JPA 的实现 -->
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
            <!-- 添加持久化类 -->
            <class>com.dx.jpa.singlemanytoone.Customer</class>
            <class>com.dx.jpa.singlemanytoone.Order</class>
            <properties>
                <!-- 数据库的相关配置 -->
                <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
                <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/jpa" />
                <property name="javax.persistence.jdbc.user" value="root" />
                <property name="javax.persistence.jdbc.password" value="root" />
                <!-- 指定方言 
                MySQL                org.hibernate.dialect.MySQLDialect
                MySQL with InnoDB    org.hibernate.dialect.MySQLInnoDBDialect
                MySQL with MyISAM    org.hibernate.dialect.MySQLMyISAMDialect
                MySQL5                org.hibernate.dialect.MySQL5Dialect
                MySQL5 with InnoDB    org.hibernate.dialect.MySQL5InnoDBDialect
                -->
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
                <property name="hibernate.show_sql" value="true" />
                <property name="hibernate.format_sql" value="true" />
                <!-- 
                create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。<br>
                create-drop :每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。<br>
                update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。<br>
                validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 <br> 
                -->
                <property name="hibernate.hbm2ddl.auto" value="update" />            
            </properties>
        </persistence-unit>
    </persistence>
    View Code

    此时在order表中创建了外键关联关系:

    添加测试

    添加测试函数:

        @Test
        public void testPersist() {
            Customer customer = new Customer();
            customer.setFullName("AA");
            customer.setAge(26);
            customer.setBirth(new Date());
            customer.setCreateDate(new Date());
    
            Order order1 = new Order();
            order1.setName("O-AA-01");
    
            Order order2 = new Order();
            order2.setName("O-AA-02");
            
            customer.getOrders().add(order1);
            customer.getOrders().add(order2);
            
            entityManager.persist(customer);
            entityManager.persist(order1);
            entityManager.persist(order2);
        }

    此时执行sql如下:

    Hibernate: 
        select
            next_val as id_val 
        from
            hibernate_sequence for update
                
    Hibernate: 
        update
            hibernate_sequence 
        set
            next_val= ? 
        where
            next_val=?
    Hibernate: 
        select
            next_val as id_val 
        from
            hibernate_sequence for update
                
    Hibernate: 
        update
            hibernate_sequence 
        set
            next_val= ? 
        where
            next_val=?
    Hibernate: 
        select
            next_val as id_val 
        from
            hibernate_sequence for update
                
    Hibernate: 
        update
            hibernate_sequence 
        set
            next_val= ? 
        where
            next_val=?
    Hibernate: 
        insert 
        into
            jpa_customer
            (age, birth, createDate, FULL_NAME, id) 
        values
            (?, ?, ?, ?, ?)
    Hibernate: 
        insert 
        into
            jpa_order
            (name, id) 
        values
            (?, ?)
    Hibernate: 
        insert 
        into
            jpa_order
            (name, id) 
        values
            (?, ?)
    Hibernate: 
        update
            jpa_order 
        set
            CUSTOMER_ID=? 
        where
            id=?
    Hibernate: 
        update
            jpa_order 
        set
            CUSTOMER_ID=? 
        where
            id=?
    View Code

    此时并不是因为customer,order保存顺序导致的(即使调换添加先后顺序也会多处update语句),因为多的一端在插入时不会插入外键列,因此一定会多处update语句。

    查询测试

    添加测试函数:

        @Test
        public void testFind() {
            Customer customer = entityManager.find(Customer.class, 1);
            System.out.println(customer.getFullName());
            System.out.println(customer.getOrders().size());
        }
    View Code

    执行打印结果:

    Hibernate: 
        select
            customer0_.id as id1_0_0_,
            customer0_.age as age2_0_0_,
            customer0_.birth as birth3_0_0_,
            customer0_.createDate as createDa4_0_0_,
            customer0_.FULL_NAME as FULL_NAM5_0_0_ 
        from
            jpa_customer customer0_ 
        where
            customer0_.id=?
    AA
    Hibernate: 
        select
            orders0_.CUSTOMER_ID as CUSTOMER3_1_0_,
            orders0_.id as id1_1_0_,
            orders0_.id as id1_1_1_,
            orders0_.name as name2_1_1_ 
        from
            jpa_order orders0_ 
        where
            orders0_.CUSTOMER_ID=?
    2

    从打印结果上可以看出默认采用懒加载的方式,修改Customer.java中的@OneToMany()中的fetch属性为:@OneToMany(fetch=FetchType.EAGER),此时才会出现非懒加载:

    此时,再次执行插叙测试函数,执行打印结果如下:

    Hibernate: 
        select
            customer0_.id as id1_0_0_,
            customer0_.age as age2_0_0_,
            customer0_.birth as birth3_0_0_,
            customer0_.createDate as createDa4_0_0_,
            customer0_.FULL_NAME as FULL_NAM5_0_0_,
            orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
            orders1_.id as id1_1_1_,
            orders1_.id as id1_1_2_,
            orders1_.name as name2_1_2_ 
        from
            jpa_customer customer0_ 
        left outer join
            jpa_order orders1_ 
                on customer0_.id=orders1_.CUSTOMER_ID 
        where
            customer0_.id=?
    AA
    2

    修改测试

    修改测试函数:

        @Test
        public void testUpdate() {
            Customer customer = entityManager.find(Customer.class, 1);
            customer.getOrders().iterator().next().setName("O-XX-01");
        }

    此时执行打印结果为:

    Hibernate: 
        select
            customer0_.id as id1_0_0_,
            customer0_.age as age2_0_0_,
            customer0_.birth as birth3_0_0_,
            customer0_.createDate as createDa4_0_0_,
            customer0_.FULL_NAME as FULL_NAM5_0_0_,
            orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
            orders1_.id as id1_1_1_,
            orders1_.id as id1_1_2_,
            orders1_.name as name2_1_2_ 
        from
            jpa_customer customer0_ 
        left outer join
            jpa_order orders1_ 
                on customer0_.id=orders1_.CUSTOMER_ID 
        where
            customer0_.id=?
    Hibernate: 
        update
            jpa_order 
        set
            name=? 
        where

    注意:这时@OneToMany(fetch=FetchType.EAGER)

    删除测试

    删除测试函数:

        @Test
        public void testRemove() {        
             Customer customer = entityManager.find(Customer.class, 4);
             entityManager.remove(customer);
        }

    此时customer表内容记录如下:

    order表记录如下:

    此时执行删除,可以删除成功,删除后customer.id=4的记录被删除了,而order表中id=5,6记录的customer_id值被置为null。

    删除后结果为:

    customer表记录:

    order表记录:

    从执行打印语句可以看出:

    Hibernate: 
        select
            customer0_.id as id1_0_0_,
            customer0_.age as age2_0_0_,
            customer0_.birth as birth3_0_0_,
            customer0_.createDate as createDa4_0_0_,
            customer0_.FULL_NAME as FULL_NAM5_0_0_,
            orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
            orders1_.id as id1_1_1_,
            orders1_.id as id1_1_2_,
            orders1_.name as name2_1_2_ 
        from
            jpa_customer customer0_ 
        left outer join
            jpa_order orders1_ 
                on customer0_.id=orders1_.CUSTOMER_ID 
        where
            customer0_.id=?
    Hibernate: 
        update
            jpa_order 
        set
            CUSTOMER_ID=null 
        where
            CUSTOMER_ID=?
    Hibernate: 
        delete 
        from
            jpa_customer 
        where
            id=?

     实际上,我们可以通过配置@OneToMany的级联删除属性,可以通过删除customer来实现级联删除的。

    修改Customer.java中的@OneToMany注解信息:

    这里修改配置后Customer的getOrders()方法的注解为:

        // 映射一对多的关联关系
        // @JoinColumn 用来映射一对多的关联关系
        // @OneToMany 用来映射外键列
        @JoinColumn(name = "CUSTOMER_ID")
        @OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.REMOVE)
        public Set<Order> getOrders() {
            return orders;
        }

    此时,测试通过删除customer.id=1的记录,测试结果可以成功级联删除,执行打印结果为:

    Hibernate: 
        select
            customer0_.id as id1_0_0_,
            customer0_.age as age2_0_0_,
            customer0_.birth as birth3_0_0_,
            customer0_.createDate as createDa4_0_0_,
            customer0_.FULL_NAME as FULL_NAM5_0_0_,
            orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
            orders1_.id as id1_1_1_,
            orders1_.id as id1_1_2_,
            orders1_.name as name2_1_2_ 
        from
            jpa_customer customer0_ 
        left outer join
            jpa_order orders1_ 
                on customer0_.id=orders1_.CUSTOMER_ID 
        where
            customer0_.id=?
    Hibernate: 
        update
            jpa_order 
        set
            CUSTOMER_ID=null 
        where
            CUSTOMER_ID=?
    Hibernate: 
        delete 
        from
            jpa_order 
        where
            id=?
    Hibernate: 
        delete 
        from
            jpa_order 
        where
            id=?
    Hibernate: 
        delete 
        from
            jpa_customer 
        where
            id=?
  • 相关阅读:
    BZOJ 1726: [Usaco2006 Nov]Roadblocks第二短路
    BZOJ 1708: [Usaco2007 Oct]Money奶牛的硬币
    BZOJ 1642: [Usaco2007 Nov]Milking Time 挤奶时间
    BZOJ 1611: [Usaco2008 Feb]Meteor Shower流星雨
    BZOJ 1610: [Usaco2008 Feb]Line连线游戏
    BZOJ 1609: [Usaco2008 Feb]Eating Together麻烦的聚餐
    BZOJ 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头
    BZOJ 1606: [Usaco2008 Dec]Hay For Sale 购买干草
    BZOJ 1083: [SCOI2005]繁忙的都市
    STL set的用法
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/9226262.html
Copyright © 2011-2022 走看看