JPA學習---第九節:JPA中的一對多雙向關聯與級聯操作


一、一對多雙向關聯與級聯操作

1、創建項目,配置文件代碼如下:

<?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">
  <!--    
     name屬性用於定義持久化單元的名字 (name必選,空值也合法);   
     transaction-type 指定事務類型(可選)    
  --> 
  <persistence-unit name="learn_jpa" transaction-type="RESOURCE_LOCAL">
          <provider>org.hibernate.ejb.HibernatePersistence</provider>
           <!-- hibernate.dialect 指定數據庫的方言 -->
         <!-- <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
         <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
         <property name="hibernate.connection.username" value="learn_orcl"/>
         <property name="hibernate.connection.password" value="learn_orcl"/>
         <property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:learn_data?useUnicode=true&amp;characterEncoding=UTF-8"/>
         <property name="hibernate.hbm2ddl.auto" value="update"/> -->
         <!-- hibernate.hbm2ddl.auto參數的作用主要用於:自動創建|更新|驗證數據庫表結構 -->
         <!-- 
         create:每次加載hibernate時都會刪除上一次的生成的表,然后根據你的model類再重新來生成新表,
         哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。
         create-drop:每次加載hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。
         update:最常用的屬性,第一次加載hibernate時根據model類會自動建立起表的結構(前提是先建立好數據庫),
         以后加載hibernate時根據 model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。
         要注意的是當部署到服務器后,表結構是不會被馬上建立起來的,是要等 應用第一次運行起來后才會。
         validate:每次加載hibernate時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,
         但是會插入新值。
          -->
          
         <properties>
            <!-- 數據庫方言 -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
            <!-- 數據庫驅動 -->
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
            <!-- 數據庫用戶名 -->
            <property name="hibernate.connection.username" value="root" />
            <!-- 數據庫密碼 -->
            <property name="hibernate.connection.password" value="123456" />
            <!-- 數據庫連接URL -->
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/learn_jpa?useUnicode=true&amp;characterEncoding=UTF8"/>
            <!-- 最大抓取深度 -->
            <property name="hibernate.max_fetch_depth" value="3" />
            <!-- 更新方式創建庫表 -->
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <!-- 顯示SQL -->
            <property name="hibernate.show_sql" value="false" />
            <!-- 格式SQL -->
            <property name="hibernate.format_sql" value="true" />
        </properties>
  </persistence-unit>
</persistence>

2、創建訂單實體類,代碼如下:

package learn.jpa.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;

/**
 * 訂單
 */
@Entity // 定義類為實體類
public class Order {

    private String orderid;
    private float amount = 0f;
    private Set<OrderItem> item = new HashSet<OrderItem>();
    
    @Id // 實體標識符,因為是字符串類型,所有不能用 @GeneratedValue,只能人為的賦值
    @Column(length=20)
    public String getOrderid() {
        return orderid;
    }
    public void setOrderid(String orderid) {
        this.orderid = orderid;
    }
    @Column(nullable = false)
    public float getAmount() {
        return amount;
    }
    public void setAmount(float amount) {
        this.amount = amount;
    }
    @OneToMany(cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE})
    public Set<OrderItem> getItem() {
        return item;
    }
    public void setItem(Set<OrderItem> item) {
        this.item = item;
    }
    
}
/**
 * 1 - N
 * 多的一端為關系維護端,關系維護端負責外鍵記錄的更新
 *
 */

3、創建訂單項實體類,代碼如下:

package learn.jpa.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
 * 訂單項
 */
@Entity // 定義類為實體類
public class OrderItem {

    private int id;
    private String productName;
    private float sellPrice = 0f;
    private Order order;
    
    @Id // 實體標識符
    @GeneratedValue // 主鍵自動增長
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    
    @Column(length=40,nullable=false)
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    
    @Column(nullable=false)
    public float getSellPrice() {
        return sellPrice;
    }
    public void setSellPrice(float sellPrice) {
        this.sellPrice = sellPrice;
    }
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
}

注解:

1、@OneToMany(fetch=FetchType,cascade=CascadeType)

@OneToMany描述一個一對多的關聯,該屬性應該為集體類型,在數據庫中並沒有實際字段.

fetch:表示該屬性的讀取策略,有EAGER和LAZY兩種,分別表示主支抓取和延遲加載,默認為EAGER. 

cascade:表示級聯操作策略,對於OneToMany類型的關聯非常重要,通常該實體更新或刪除時,其關聯的實體也應當被更新或刪除

(1)、CascadeType.MERGE級聯更新:若items屬性修改了那么order對象保存時同時修改items里的對象。對應EntityManager的merge方法

(2)、CascadeType.PERSIST級聯刷新:獲取order對象里也同時也重新獲取最新的items時的對象。對應EntityManager的refresh(object)方法有效。即會重新查詢數據庫里的最新數據 

(3)、CascadeType.REFRESH級聯保存:對order對象保存時也對items里的對象也會保存。對應EntityManager的presist方法

(4)、CascadeType.REMOVE級聯刪除:對order對象刪除也對items里的對象也會刪除。對應EntityManager的remove方法

CascadeType.PERSIST只有A類新增時,會級聯B對象新增。若B對象在數據庫存(跟新)在則拋異常(讓B變為持久態)

CascadeType.MERGE指A類新增或者變化,會級聯B對象(新增或者變化)

CascadeType.REMOVE只有A類刪除時,會級聯刪除B類;

CascadeType.ALL包含所有;

綜上:大多數情況用CascadeType.MERGE就能達到級聯跟新又不報錯,用CascadeType.ALL時要斟酌下CascadeType.REMOVE

optional:是否允許該字段為null,該屬性應該根據數據庫表的外鍵約束來確定,默認為true

二、JPA中的一對多延遲加載與關系維護

1、訂單實體類,代碼:

package learn.jpa.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * 訂單
 */
@Entity // 定義類為實體類
@Table(name="orders")
public class Order {

    private String orderid;
    private float amount = 0f;
    private Set<OrderItem> item = new HashSet<OrderItem>();
    
    @Id // 實體標識符,因為是字符串類型,所有不能用 @GeneratedValue,只能人為的賦值
    @Column(length=20)
    public String getOrderid() {
        return orderid;
    }
    public void setOrderid(String orderid) {
        this.orderid = orderid;
    }
    @Column(nullable = false)
    public float getAmount() {
        return amount;
    }
    public void setAmount(float amount) {
        this.amount = amount;
    }
    /**
     * 如果是一對多或多對多 fetch 默認是延遲加載,反之是立即加載
     * mappedBy="order" 表示由實體 OrderItem 中的 order 屬性維護
     * @return
     */
    @OneToMany(cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},
            fetch=FetchType.LAZY,mappedBy="order")
    public Set<OrderItem> getItem() {
        return item;
    }
    public void setItem(Set<OrderItem> item) {
        this.item = item;
    }

    public void addOrderItem(OrderItem orderItem){
        orderItem.setOrder(this);
        this.item.add(orderItem);
    }
    
}
/**
 * 1 - N
 * 多的一端為關系維護端,關系維護端負責外鍵記錄的更新
 *
 */

mappedBy只有在雙向關聯時,才會使用這個屬性

mappedBy=”另一方的關系引用屬性”

2、訂單項實體類,代碼:

package learn.jpa.entity;

import javax.persistence.CascadeType;
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.ManyToOne;
import javax.persistence.Table;

/**
 * 訂單項
 */
@Entity // 定義類為實體類
public class OrderItem {

    private int id;
    private String productName;
    private float sellPrice = 0f;
    private Order order;
    
    @Id // 實體標識符
    @GeneratedValue // 主鍵自動增長
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    
    @Column(length=40,nullable=false)
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    
    @Column(nullable=false)
    public float getSellPrice() {
        return sellPrice;
    }
    public void setSellPrice(float sellPrice) {
        this.sellPrice = sellPrice;
    }
    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.EAGER,optional=false)
    @JoinColumn(name="order_id")
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
}

joinColumns屬性表示,在保存關系中的表中,所保存關聯關系的外鍵的字段。並配合@JoinColumn標記使用。

3、測試保存,代碼如下:

package learn.jpa.test;

import static org.junit.Assert.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import learn.jpa.entity.Order;
import learn.jpa.entity.OrderItem;

import org.junit.Test;

public class OneToManyTest {

    /**
     * 測試數據庫是否可以生成表
     */
    @Test
    public void test() {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("learn_jpa");
        factory.close();
    }

    @Test
    public void save(){
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("learn_jpa");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();   // 開啟事務
        Order order = new Order();
        order.setAmount(56f);
        order.setOrderid("SE001");
        
        OrderItem item1 = new OrderItem();
        item1.setProductName("足球");
        item1.setSellPrice(32f);
        
        OrderItem item2 = new OrderItem();
        item2.setProductName("羽毛球");
        item2.setSellPrice(24f);
        
        order.addOrderItem(item1);
        order.addOrderItem(item2);
        
        em.persist(order);
        em.getTransaction().commit();
        em.close();
        factory.close();
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM