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&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&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中的一对多双向关联与级联操作的更多相关文章
- JPA中的一对多双向关联与级联操作
学习Spring有两周时间了 , 个人觉得服务端主要实现的是数据关系的维护和数据结构的制定 , 以及由业务需求产生的CRUD , 只要保证对前端提供的接口稳定高效响应 , 具体的前端实现完全不关心. ...
- JPA学习笔记1——JPA基础
1.JPA简介: Java持久化规范,是从EJB2.x以前的实体Bean(Entity bean)分离出来的,EJB3以后不再有实体bean,而是将实体bean放到JPA中实现.JPA是sun提出的一 ...
- python学习第九讲,python中的数据类型,字符串的使用与介绍
目录 python学习第九讲,python中的数据类型,字符串的使用与介绍 一丶字符串 1.字符串的定义 2.字符串的常见操作 3.字符串操作 len count index操作 4.判断空白字符,判 ...
- JPA学习笔记1——JPA基础 (转自CSDN)
http://blog.csdn.net/chjttony/article/details/6086298 1.JPA简介: Java持久化规范,是从EJB2.x以前的实体Bean(Entity be ...
- Hibernate从入门到精通(九)一对多双向关联映射
上次的博文Hibernate从入门到精通(八)一对多单向关联映射中,我们讲解了一下一对多单向映射的相关内容,这次我们讲解一下一对多双向映射的相关内容. 一对多双向关联映射 一对多双向关联映射,即在一的 ...
- Hibernate(九)一对多双向关联映射
上次的博文Hibernate从入门到精通(八)一对多单向关联映射中,我们讲解了一下一对多单向映射的相关 内容,这次我们讲解一下一对多双向映射的相关内容. 一对多双向关联映射 一对多双向关联映 射,即在 ...
- Hibernate 一对多双向关联Demo
以Classes[班级]和Student[学生]为例的Demo //Classes.java public class Classes implements Serializable { privat ...
- hibernate 一对多双向关联 详解
一.解析: 1. 一对多双向关联也就是说,在加载班级时,能够知道这个班级所有的学生. 同时,在加载学生时,也能够知道这个学生所在的班级. 2.我们知道,一对多关联映射和多对一关联映射是一样的,都是在 ...
- Hibernate中用注解配置一对多双向关联和多对一单向关联
Hibernate中用注解配置一对多双向关联和多对一单向关联 Hibernate提供了Hibernate Annotations扩展包,使用注解完成映射.在Hibernate3.3之前,需单独下载注解 ...
随机推荐
- JS基础学习1——什么是基础js类和原型?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Oracle 11g 客户端 下载地址
摘自: http://blog.csdn.net/davidhsing/article/details/8271845 Oracle Database Instant Client 11g 11.2. ...
- Overcome the Dilemma of "unlock" and "trust"
When examining an Android phone, we have to overcome some barriers first so that we could extract da ...
- RPC通信(Windows版、Android版)
1.RPC通信模型 2.调用截图 服务器端 PC客户端: Android客户端: 3.remotetea jrpcgen.jar:生成Java源文件 oncrpc.jar:框架通信调用 portmap ...
- box2d 遍历世界中 body 的方法
大家都知道,循环遍历有很多方法,在box2d中大家普遍使用while和for循环来遍历世界,那什么时候使用for,什么时候使用while呢? 当循环中不设计body删除的时候,使用for循环,即: C ...
- (五)、nodejs使用bootstrap的样式进行分页
一.page方法 /****************************************************** * Created User: * Created Time: 201 ...
- Curses library not found. Please install appropriate package
今天安装mysql-5.5.3-m3的时候,报下面的错误: -- Could NOT find OpenSSL (missing: OPENSSL_LIBRARIES OPENSSL_INCLUDE_ ...
- 关于SQL表联接
以SQL2008为例,Microsoft SQL Server 2008支持四种表运算符-JOIN,APPLY,PIVOT,UNPIVOT.JOIN表运算符是ANSI标准,而其他三种是T-SQL对标准 ...
- luigi学习6--parameters详解
parameter就好比是一个task的构造方法.luigi要求你在类的scope上定义parameter. 如下面就是一个定义parameter的例子: class DailyReport(luig ...
- Tomcat配置虚拟主机后的登录验证码问题
先描述一下问题现象,在本地测试运行一个java web网站,一切正常.但把网站部署到Linux服务器上后,发现登录出了问题,提示验证码输入不正确.登录时需要输入验证码,而验证码的原值是先存入sessi ...