• JPA学习(四、JPA_映射关联关系)


    框架学习之JPA(四)

    JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

    Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

    学习视频:尚硅谷框架jpa学习(有兴趣的同学留言邮箱)

    使用软件:eclipse

    Java版本:jdk8

    本节目录

    四、JPA_映射关联关系

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

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

            3.映射双向多对一的关联关系

            4.映射双向一对一的关联关系

            5.映射双向多对多的关联关系

    四、JPA_映射关联关系

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

    创建Order

    package hue.edu.xiong.jpa;
    
    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.ManyToOne;
    
    import javax.persistence.Table;
    
    @Entity
    
    @Table(name="JPA_ORDERS")
    
    public class Order {
    
    @Id
    
    @GeneratedValue(strategy=GenerationType.AUTO)
    
    private Integer id;
    
    @Column(name="ORDER_NAME")
    
    private String orderName;
    
    //映射单向n-1的关联关系
    
    //使用@ManyToIne来映射多对一的关联关系
    
    //使用@JoinColumn来映射外键
    
        //上课学到的原则,对方永远是一,即多个我对应一个对方,即多对一
    
    @ManyToOne
    
    @JoinColumn(name="CUSTOMER_ID")
    
    private Customer customer;
    
    //get,set略,请自行补充
    
    }
    

      

    保存测试:

    @Test
    
    public void testManyToOnePersist() {
    
    Customer customer = new Customer();
    
    customer.setAge(12);
    
    customer.setEmail("937724308@qq.com");
    
    customer.setLastName("xiong");
    
    customer.setBirth(new Date());
    
    customer.setCreatedTime(new Date());
    
    Order order1 = new Order();
    
    order1.setOrderName("O-FF-1");
    
    Order order2 = new Order();
    
    order2.setOrderName("O-FF-2");
    
    //设置关联关系
    
    order1.setCustomer(customer);
    
    order2.setCustomer(customer);
    
    //执行保存操作
    
    entityManager.persist(customer);
    
    entityManager.persist(order1);
    
    entityManager.persist(order2);
    
    }
    

      

    //修改保存顺序
    
    entityManager.persist(order1);
    
    entityManager.persist(order2);
    
    entityManager.persist(customer);
    

      

    第一个测试会发现数据库中是三个insert操作

    第二个测试修改顺序之后发现是三个insert操作,再是两个update操作

    保存多对一时,建议先保存1的一端,然后保存n的一端这样不会有额外的update语句

    获取测试:

    //默认情况下使用左外连接方式来获取N的一端的对象和其关联的1的一端的对象
    
    //可使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略
    
    @Test
    
    public void testManyToOneFind() {
    
    Order order = entityManager.find(Order.class, 1);
    
    System.out.println(order.getOrderName());
    
    System.out.println(order.getCustomer().getLastName());
    
    }
    ------------------------------------------------------
    //懒加载模式
    
    //映射单向n-1的关联关系
    
    //使用@ManyToIne来映射多对一的关联关系
    
    //使用@JoinColumn来映射外键
    
    //可使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略
    
    @ManyToOne(fetch=FetchType.LAZY)
    
    @JoinColumn(name="CUSTOMER_ID")
    
    private Customer customer;
    

      

    删除测试:

    //不能直接删除 1 的一端, 因为有外键约束.
    
    @Test
    
    public void testManyToOneRemove(){
    
    // Order order = entityManager.find(Order.class, 1);
    
    // entityManager.remove(order);
    
    Customer customer = entityManager.find(Customer.class, 5);
    
    entityManager.remove(customer);
    
    }
    

      

    修改测试:

     

    //可以修改外键对应的对象的值将"xiong"->"FFF"
    
    @Test
    
    public void testManyToOneUpdate(){
    
    Order order = entityManager.find(Order.class, 2);
    
    order.getCustomer().setLastName("FFF");
    
    }
    

      

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

    修改Order类,把Customer全部注解掉

    package hue.edu.xiong.jpa;
    
     
    
    import javax.persistence.Column;
    
    import javax.persistence.Entity;
    
    import javax.persistence.GeneratedValue;
    
    import javax.persistence.GenerationType;
    
    import javax.persistence.Id;
    
    import javax.persistence.Table;
    
     
    
    @Entity
    
    @Table(name="JPA_ORDERS")
    
    public class Order {
    
     
    
    @Id
    
    @GeneratedValue(strategy=GenerationType.AUTO)
    
    private Integer id;
    
     
    
    @Column(name="ORDER_NAME")
    
    private String orderName;
    
     
    
    // //映射单向n-1的关联关系
    
    // //使用@ManyToIne来映射多对一的关联关系
    
    // //使用@JoinColumn来映射外键
    
    // //可使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略
    
    // @ManyToOne(fetch=FetchType.LAZY)
    
    // @JoinColumn(name="CUSTOMER_ID")
    
    // private Customer customer;
    
    //get,set略,请自行补充
    
    }
    

      

    修改Customer类,增加Set<Order> orders,并且设置一对多关系

    package hue.edu.xiong.jpa;
    
     
    
    import java.util.Date;
    
    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;
    
    @Table(name = "JPA_CUSTOMERS")
    
    @Entity
    
    public class Customer {
    
    @Id
    
    @GeneratedValue(strategy = GenerationType.AUTO)
    
    private Integer id;
    
    @Column(name = "LAST_NAME")
    
    private String lastName;
    
    private String email;
    
    private Integer age;
    
    @Temporal(TemporalType.DATE)
    
    private Date birth;
    
    @Temporal(TemporalType.TIMESTAMP)
    
    private Date createdTime;
    
     
    
    //设置单向1-n关联关系
    
    @OneToMany
    
    @JoinColumn(name="CUSTOMER_ID")
    
    private Set<Order> orders;
    
    }

    保存测试:

    //单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
    
    //因为 n 的一端在插入时不会同时插入外键列.
    
    @Test
    
    public void testOneToManyPersist(){
    
    Customer customer = new Customer();
    
    customer.setAge(18);
    
    customer.setBirth(new Date());
    
    customer.setCreatedTime(new Date());
    
    customer.setEmail("mm@163.com");
    
    customer.setLastName("MM");
    
     
    
    Order order1 = new Order();
    
    order1.setOrderName("O-MM-1");
    
     
    
    Order order2 = new Order();
    
    order2.setOrderName("O-MM-2");
    
     
    
    //建立关联关系
    
    customer.getOrders().add(order1);
    
    customer.getOrders().add(order2);
    
     
    
    //执行保存操作
    
    entityManager.persist(customer);
    
     
    
    entityManager.persist(order1);
    
    entityManager.persist(order2);
    
    }
    • 单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
    • 因为 n 的一端在插入时不会同时插入外键列.

    查找测试:

    //默认对关联的多的一方使用懒加载的加载策略.
    
    //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
    
    @Test
    
    public void testOneToManyFind(){
    
    Customer customer = entityManager.find(Customer.class, 9);
    
    System.out.println(customer.getLastName());
    
     
    
    System.out.println(customer.getOrders().size());
    
    }
    
    • 默认是使用懒加载模式,可以修改为其他策略模式,怎样修改看下面的删除测试第二个表格内容

    删除测试:

    //默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除.
    
    //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.
    
    @Test
    
    public void testOneToManyRemove(){
    
    Customer customer = entityManager.find(Customer.class, 8);
    
    entityManager.remove(customer);
    
    }
    

      

    //设置单向1-n关联关系
    
    //使用 @OneToMany 来映射 1-n 的关联关系
    
    //使用 @JoinColumn 来映射外键列的名称
    
    //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
    
    //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.
    
    @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE})
    
    @JoinColumn(name="CUSTOMER_ID")
    
    private Set<Order> orders;
    • 将外键修改为空之后再删除
    • 将外键全部删除之后再删除

    修改测试:

    @Test
    
    public void testUpdate(){
    
    Customer customer = entityManager.find(Customer.class, 10);
    
     
    
    customer.getOrders().iterator().next().setOrderName("O-XXX-10");
    
    }
    

      

    3.映射双向多对一的关联关系

    • 若是双向 1-n 的关联关系, 执行保存时
    • 若先保存 n 的一端, 再保存 1 的一端, 默认情况下, 会多出 n UPDATE 语句.
    • 若先保存 1 的一端, 则会多出 n UPDATE 语句
    • 在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系,  1 的一方不维护关联系, 这样会有效的减少 SQL 语句.
    • 注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, @OneToMany 端就不能再使用 @JoinColumn属性了.
    • 放弃维护关联关系,不使用JoinColumn标签,在@OneToMany 中使用 mappedBy 属性
    // @JoinColumn(name="CUSTOMER_ID")
    
    @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")

    自我理解,就是把上面两个关系组合起来,尽量使用多对一的关系,其他都一样

     

    4.映射双向一对一的关联关系

    创建两个类ManagerDepartment

     

    package hue.edu.xiong.jpa;
    
     
    
    import javax.persistence.Column;
    
    import javax.persistence.Entity;
    
    import javax.persistence.FetchType;
    
    import javax.persistence.GeneratedValue;
    
    import javax.persistence.Id;
    
    import javax.persistence.OneToOne;
    
    import javax.persistence.Table;
    
     
    
    @Table(name = "JPA_MANAGERS")
    
    @Entity
    
    public class Manager {
    
    @Id
    
    @GeneratedValue
    
    private Integer id;
    
    @Column(name = "MGR_NAME")
    
    private String mgrName;
    
    // 对于不维护关联关系, 没有外键的一方, 使用 @OneToOne 来进行映射, 建议设置 mappedBy=true
    
    @OneToOne(mappedBy = "mgr")
    
    private Department dept;
    
     
    
    //get,set略,请自行补充
    
    }
    
     
    

     

      

    package hue.edu.xiong.jpa;
    
     
    
    import javax.persistence.Column;
    
    import javax.persistence.Entity;
    
    import javax.persistence.FetchType;
    
    import javax.persistence.GeneratedValue;
    
    import javax.persistence.Id;
    
    import javax.persistence.JoinColumn;
    
    import javax.persistence.OneToOne;
    
    import javax.persistence.Table;
    
     
    
    @Table(name = "JPA_DEPARTMENTS")
    
    @Entity
    
    public class Department {
    
    @Id
    
    @GeneratedValue
    
    private Integer id;
    
    @Column(name = "DEPT_NAME")
    
    private String deptName;
    
    // 使用 @OneToOne 来映射 1-1 关联关系。
    
    // 若需要在当前数据表中添加主键则需要使用 @JoinColumn 来进行映射. 注意, 1-1 关联关系, 所以需要添加 unique=true
    
    @JoinColumn(name = "MGR_ID", unique = true)
    
    @OneToOne(fetch = FetchType.LAZY)
    
    private Manager mgr;
    
     
    
    //get,set略,请自行补充
    
     
    
    }
    

      

    保存测试:

    //双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.
    
    @Test
    
    public void testOneToOnePersistence(){
    
    Manager mgr = new Manager();
    
    mgr.setMgrName("M-BB");
    
     
    
    Department dept = new Department();
    
    dept.setDeptName("D-BB");
    
     
    
    //设置关联关系
    
    mgr.setDept(dept);
    
    dept.setMgr(mgr);
    
     
    
    //执行保存操作
    
    entityManager.persist(mgr);
    
    entityManager.persist(dept);
    
    }
    

      

    • l双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.

    查找测试:

    //1.默认情况下, 若获取维护关联关系的一方, 则会通过左外连接获取其关联的对象.
    
    //但可以通过 @OntToOne 的 fetch 属性来修改加载策略.
    
    @Test
    
    public void testOneToOneFind(){
    
    Department dept = entityManager.find(Department.class, 1);
    
    System.out.println(dept.getDeptName());
    
    System.out.println(dept.getMgr().getClass().getName());
    
    }
    

      

    //1. 默认情况下, 若获取不维护关联关系的一方, 则也会通过左外连接获取其关联的对象.
    
    //可以通过 @OneToOne 的 fetch 属性来修改加载策略. 但依然会再发送 SQL 语句来初始化其关联的对象
    
    //这说明在不维护关联关系的一方, 不建议修改 fetch 属性.
    
    @Test
    
    public void testOneToOneFind2(){
    
    Manager mgr = entityManager.find(Manager.class, 1);
    
    System.out.println(mgr.getMgrName());
    
     
    
    System.out.println(mgr.getDept().getClass().getName());
    
    }

     

    5.映射双向多对多的关联关系

    创建两个类itemCategory

     

    package hue.edu.xiong.jpa;
    
     
    
    import java.util.HashSet;
    
    import java.util.Set;
    
     
    
    import javax.persistence.Column;
    
    import javax.persistence.Entity;
    
    import javax.persistence.GeneratedValue;
    
    import javax.persistence.Id;
    
    import javax.persistence.JoinColumn;
    
    import javax.persistence.JoinTable;
    
    import javax.persistence.ManyToMany;
    
    import javax.persistence.Table;
    
     
    
    @Table(name="JPA_ITEMS")
    
    @Entity
    
    public class Item {
    
     
    
    @Id
    
    @GeneratedValue
    
    private Integer id;
    
    @Column(name="ITEM_NAME")
    
    private String itemName;
    
     
    
    //使用 @ManyToMany 注解来映射多对多关联关系
    
    //使用 @JoinTable 来映射中间表
    
    //1. name 指向中间表的名字
    
    //2. joinColumns 映射当前类所在的表在中间表中的外键
    
    //2.1 name 指定外键列的列名
    
    //2.2 referencedColumnName 指定外键列关联当前表的哪一列
    
    //3. inverseJoinColumns 映射关联的类所在中间表的外键
    
    @JoinTable(name="ITEM_CATEGORY",
    
    joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},
    
    inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})
    
    @ManyToMany
    
    private Set<Category> categories = new HashSet<>();
    
    //get,set略,请自行补充
    
    }
    

     

      

    package hue.edu.xiong.jpa;
    
     
    
    import java.util.HashSet;
    
    import java.util.Set;
    
     
    
    import javax.persistence.Column;
    
    import javax.persistence.Entity;
    
    import javax.persistence.GeneratedValue;
    
    import javax.persistence.Id;
    
    import javax.persistence.ManyToMany;
    
    import javax.persistence.Table;
    
     
    
    @Table(name = "JPA_CATEGORIES")
    
    @Entity
    
    public class Category {
    
     
    
    @Id
    
    @GeneratedValue
    
    private Integer id;
    
    @Column(name = "CATEGORY_NAME")
    
    private String categoryName;
    
    @ManyToMany(mappedBy = "categories")
    
    private Set<Item> items = new HashSet<>();
    
    //get,set略,请自行补充,过分了啊,这个颜色一直调整不好
    
    }
    

      

    必须指定中间表

    • 使用 @ManyToMany 注解来映射多对多关联关系
    • 使用 @JoinTable 来映射中间表
      • name 指向中间表的名字
      • joinColumns 映射当前类所在的表在中间表中的外键
        • name 指定外键列的列名
        • referencedColumnName 指定外键列关联当前表的哪一列
      • inverseJoinColumns 映射关联的类所在中间表的外键

    典型多对多,一个学生对应多门课程,一门课程对应多个学生,学生加课程决定成绩

    保存案例:

    //多对多的保存
    
    @Test
    
    public void testManyToManyPersist(){
    
    Item i1 = new Item();
    
    i1.setItemName("i-1");
    
     
    
    Item i2 = new Item();
    
    i2.setItemName("i-2");
    
     
    
    Category c1 = new Category();
    
    c1.setCategoryName("C-1");
    
     
    
    Category c2 = new Category();
    
    c2.setCategoryName("C-2");
    
     
    
    //设置关联关系
    
    i1.getCategories().add(c1);
    
    i1.getCategories().add(c2);
    
     
    
    i2.getCategories().add(c1);
    
    i2.getCategories().add(c2);
    
     
    
    c1.getItems().add(i1);
    
    c1.getItems().add(i2);
    
     
    
    c2.getItems().add(i1);
    
    c2.getItems().add(i2);
    
     
    
    //执行保存
    
    entityManager.persist(i1);
    
    entityManager.persist(i2);
    
    entityManager.persist(c1);
    
    entityManager.persist(c2);
    
    }

    查找案例:

    //对于关联的集合对象, 默认使用懒加载的策略.
    
    //使用维护关联关系的一方获取, 还是使用不维护关联关系的一方获取, SQL 语句相同.
    
    @Test
    
    public void testManyToManyFind(){
    
    // Item item = entityManager.find(Item.class, 5);
    
    // System.out.println(item.getItemName());
    
    //
    
    // System.out.println(item.getCategories().size());
    
     
    
    Category category = entityManager.find(Category.class, 3);
    
    System.out.println(category.getCategoryName());
    
    System.out.println(category.getItems().size());
    
    }
    

      

  • 相关阅读:
    Java垃圾收集学习笔记
    好IT男不能“淫”-谈IT人员目前普遍存在的“A情绪”
    亲密接触Redis-第三天(Redis的Load Balance)
    数据库面试常问的一些基本概念
    Mina的ssl加密
    Mina入门教程(二)----Spring4 集成Mina
    Mina Session
    Mina入门实例(一)
    java keytool生成ssl加密密钥
    Python学习(一)——数据类型
  • 原文地址:https://www.cnblogs.com/xzmxddx/p/9280128.html
Copyright © 2020-2023  润新知