JPA学习---第九节:JPA中的一对多双向关联与级联操作

摘要:
持久性单元名称=“learn_jpa”事务类型=“RESOURCE_LOCAL”>--Hibernate.dialect指定数据库的方言-->propertyname=“hibernate.connection.username”value=“learn_orcl”/>

一、一对多双向关联与级联操作

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();
    }
}

免责声明:文章转载自《JPA学习---第九节:JPA中的一对多双向关联与级联操作》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇帧率、分辨率、码流的关系引用视频全屏播放代码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Vim 命令整理

1. 文件命令 2. 模式切换 3. 移动命令 4. 书签命令 5. 修改命令 6. 可视化操作 7. 区域选择 8. 宏命令 9. 分屏 10. 系统设置命令 1. 文件命令 [:]开始的命令需要输入[Enter]结束   :q:退出 :q!:退出不保存 :qa!:退出所有文件不保存 :w:保存 :e <file>:关闭当前文件并打开另一个...

layui中radio的动态加载(进入修改页面时,设置radio)

动态设置   radio  的值让它处于选中状态 效果图 : 前端代码: <div class="layui-form-item"> <label class="layui-form-label">状态</label> <div class="layui-input-block">...

(转载)HTTP状态码

转载请见https://blog.csdn.net/Lkeven/article/details/52775296 HTTP Status Code 常见的状态码: HTTP: Status 200 – 服务器成功返回网页 HTTP: Status 404 – 请求的网页不存在 HTTP: Status 503 – 服务不可用 详解 说明: HTTP:...

ADO中记录集recordSet的使用

_RecordsetPtr使用方法 _variant_t vUsername,vID,vname; //变量声明_RecordsetPtr m_pRecordset;     //记录集CString strid;_ConnectionPtr connection;m_pRecordset.CreateInstance(__uuidof( Record...

CVE-2020-14825:Weblogic反序列化漏洞复现

全程无图,全靠编 参考:https://mp.weixin.qq.com/s?__biz=MzA4NzUwMzc3NQ==&mid=2247486336&idx=1&sn=2a054ededbc855622fe2ac6c8906aae0&chksm=90392d70a74ea46635bef3cd4fc414cef87d16...

【转】WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox

一.前言   申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等。   本文主要内容: 下拉选择控件ComboBox的自定义样式及扩展; 自定义多选控件MultiComboBox; 二.下拉选择控件ComboBox的自定义样式及扩展 2.1基本样式   先看看基础效果图:     从功能上ComboBo...