hibernate版本4.2.4
oracle 版本11g
本文主要涉及到以下几个知识点:
1.双向关联之一对一
2.双向关联之一对多
3.双向关联之多对多
对于双向关联其实有几个步骤(个人总结,如有不对,欢迎吐槽)
a.要建立双方关联,首先要各自拥有对方对象
b.指明关系维护端与关系被维护端 指明两者的级联关系
c.指明外键(或者关联表)
d.添加数据(向关系维护端添加对象,相当于向表中插入数据;向关系维护端删除对象,相当于向表中删除数据)
有一个属性需要注意,就是mappedBy,这个属性只是在关系的被维护端出现,这个属性指定了使用关系维护端的哪个属性来进行维护外键(外键指的是针对表而言,在实体对象中的话指的是某一个属性)
并且只有关系的维护端负责更新外键的记录,关系的被维护端是没有权利更新外键记录的
1.双向关联之一对一
这里介绍个人与身份证两个实体
a.新建PersonToIDCard工程 将相关的jar包引入 编写配置文件 前一篇博客已有提到 这里就不说了
配置文件persistence.xml如下
<persistence 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"
version="2.0">
<persistence-unit name="under">
<properties>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
<property name="hibernate.connection.username" value="under_test" />
<property name="hibernate.connection.password" value="under_test" />
<property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:ganew" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
</properties>
</persistence-unit>
</persistence>
直接看Person与IDCard两个实体内容
Person.java
package com.undergrowth;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
/*
* 步骤
* 1.一对一的相互关联 各自实体中拥有对方
* 2.设置关系维护端与被维护端 指定级联的关系
* 3.指明外键
* 4.添加数据
*/
@Entity
@Table(name="person_info")
public class Person {
@Id @GeneratedValue
private Integer id;
@Column(length=10,nullable=false)
private String name;
@Column(nullable=false)
private Integer age;
//all表示当person进行增删改查的时候 级联的增删改查idcard
//optional为false表示外键不能为空
@OneToOne(cascade=CascadeType.ALL,optional=false)
//JoinColumn指明idcard_id作为外键 来维护两个表的关系
@JoinColumn(name="idcard_id")
private IDCard idCard;
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;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Person(){} //用于给反射机制使用
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
public Person(String name, Integer age, IDCard idCard) {
super();
this.name = name;
this.age = age;
this.idCard = idCard;
}
}
身份证代码: IDCard.java
package com.undergrowth;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="idcard_info")
public class IDCard {
@Id @GeneratedValue
private Integer id;
@Column(length=18,nullable=false)
private String cardNum;
@Column(length=20,nullable=false)
private String issuedBy;
//mappedBy指定使用person对象的idCard这个属性来进行维护表间关系 并指明自己是关系的被维护端
@OneToOne(mappedBy="idCard")
private Person person;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCardNum() {
return cardNum;
}
public void setCardNum(String cardNum) {
this.cardNum = cardNum;
}
public String getIssuedBy() {
return issuedBy;
}
public void setIssuedBy(String issuedBy) {
this.issuedBy = issuedBy;
}
public IDCard(){} //用于给反射机制使用
public IDCard(String cardNum, String issuedBy) {
this.cardNum = cardNum;
this.issuedBy = issuedBy;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
测试单元代码: JunitTest.java
package com.junit;
import static org.junit.Assert.*;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
public class JunitTest {
@Test
public void test() {
//使用<persistence-unit name="under"> 的under来创建实体管理器工厂
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
factory.close();
}
}
test函数中的两行代码用于测试环境是否搭建成功 并且表的结构 也是在这里创建的的 如果运行test没有错误 在oracle中 两个表的结构如下:
修改test函数 实现保存
package com.junit;
import static org.junit.Assert.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
import com.undergrowth.IDCard;
import com.undergrowth.Person;
public class JunitTest {
@Test
public void test() {
//使用<persistence-unit name="under"> 的under来创建实体管理器工厂
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
EntityManager manager=factory.createEntityManager();
manager.getTransaction().begin();
IDCard idCard=new IDCard("1234567890", "中国云南");
//将关系被维护端的数据传递给关系维护端的数据 用于外键的更新
Person person=new Person("under", 20, idCard);
//因为级联关系设置了级联保存 所以这里保存person 同时也会保存idCard
manager.persist(person);
manager.getTransaction().commit();
manager.close();
factory.close();
}
}
运行test函数的效果
控制台输出:
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into idcard_info (cardNum, issuedBy, id) values (?, ?, ?)
Hibernate: insert into person_info (age, idcard_id, name, id) values (?, ?, ?, ?)
oracle中效果
至于更新、删除、查询的情况类似了
2.双向关联之一对多
这里介绍学生与成绩
先看学生 Student.java
package com.undergrowth;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/*
* 实现步骤
* 1.建立相关关联 一对多 一的一方拥有对方的集合 多的一方拥有对方的一个
* 2.指明多的一方为关系的维护端(因为逻辑关系) 指明级联关系
* 3.指明外键
* 4.添加数据(将关系被维护端的数据添加到关系维护端,用于更新外键)
*/
@Entity
public class Student {
@Id @GeneratedValue
private Integer id;
@Column(length=15,nullable=false)
private String name;
@Temporal(TemporalType.DATE) @Column(nullable=false)
private Date birthday;
@Lob @Column(nullable=false)
private String descInfo;
//指定一对多的关系 指明学生对象为关系的被维护端 使用grade对象中的student属性进行维护
//并且级联所有的更新操作
@OneToMany(mappedBy="student",cascade=CascadeType.ALL)
private Set<Grade> gardes=new HashSet<Grade>();
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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getDescInfo() {
return descInfo;
}
public void setDescInfo(String descInfo) {
this.descInfo = descInfo;
}
public Set<Grade> getGardes() {
return gardes;
}
public void setGardes(Set<Grade> gardes) {
this.gardes = gardes;
}
public Student(){} //给反射机制使用
public Student(String name, Date birthday, String descInfo) {
super();
this.name = name;
this.birthday = birthday;
this.descInfo = descInfo;
}
public void addGrades(Grade grade)
{
//将关系被维护端的数据传递给关系维护端 在表的级别体现为给外键赋值
grade.setStudent(this);
this.gardes.add(grade);
}
}
成绩 Grade.java
package com.undergrowth;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class Grade {
@Id @GeneratedValue
private Integer id;
@Column(nullable=false)
private Float grade;
@Column(length=20,nullable=false)
private String courseName;
//optional为false表示 一旦有成绩了 这个成绩必然属于某个学生的
@ManyToOne(cascade=CascadeType.REFRESH,optional=false)
//设置外键为student_id
@JoinColumn(name="student_id")
private Student student;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Float getGrade() {
return grade;
}
public void setGrade(Float grade) {
this.grade = grade;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Grade(){}
public Grade(Float grade, String courseName) {
this.grade = grade;
this.courseName = courseName;
}
}
单元测试代码: JunitTest.java
package com.junit;
import static org.junit.Assert.*;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
public class JunitTest {
@Test
public void test() {
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
factory.close();
}
}
运行test函数 oracle效果
修改test函数
package com.junit;
import static org.junit.Assert.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
import com.undergrowth.Grade;
import com.undergrowth.Student;
public class JunitTest {
@Test
public void test() throws ParseException {
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
EntityManager manager=factory.createEntityManager();
manager.getTransaction().begin();
Grade grade1=new Grade(98f, "高数");
Grade grade2=new Grade(88f, "大语");
Student student=new Student("under", new SimpleDateFormat("yyyy-MM-dd").parse("1999-9-9"), "奋斗,读书中...");
//学生中添加成绩 1:m 并且将学生的主键传递给成绩 实现外键的更新
student.addGrades(grade1);
student.addGrades(grade2);
//保存学生的信息 因为级联关系中有级联保存 所以会同时保存grade1和grade2
manager.persist(student);
manager.getTransaction().commit();
manager.close();
factory.close();
}
}
控制台输出:
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into Student (birthday, name, id, descInfo) values (?, ?, ?, ?)
Hibernate: insert into Grade (courseName, grade, student_id, id) values (?, ?, ?, ?)
Hibernate: insert into Grade (courseName, grade, student_id, id) values (?, ?, ?, ?)
oracle效果:
3.双向关联之多对多
这里介绍商品与顾客的关系
对于一对一和一对多 两者之间都是通过外键建立的关联 而对于多对多而言 这里要借助关联表来实现 意思就是说关联表用来连接两个多对多的表
商品 Commodity.java
package com.undergrowth;
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;
/*
* 1.建立相互关系 各自拥有对方的集合
* 2.指定关系维护端与被关系维护端 指定级联的关系
* 3.指定关联表 关联表的外键
* 4.向关系维护端添加数据 相当于向关联表中添加数据 向关系维护端删除数据 相当于向关联表中删除数据
*/
@Entity
public class Commodity {
@Id @GeneratedValue
private Integer id;
@Column(length=20,nullable=false)
private String commName;
@Column(nullable=false)
private Float commPrice;
@Column(length=20,nullable=false)
private String commVender;
@ManyToMany
//指定多对多的关联表为comm_consu 表中分别由两个外键 指向被维护端的外建为consu_id 维护端的外键为comm_id
@JoinTable(name="comm_consu",inverseJoinColumns=@JoinColumn(name="consu_id"),joinColumns=@JoinColumn(name="comm_id"))
private Set<Consumer> consumers=new HashSet<Consumer>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCommName() {
return commName;
}
public void setCommName(String commName) {
this.commName = commName;
}
public Float getCommPrice() {
return commPrice;
}
public void setCommPrice(Float commPrice) {
this.commPrice = commPrice;
}
public String getCommVender() {
return commVender;
}
public void setCommVender(String commVender) {
this.commVender = commVender;
}
public Set<Consumer> getConsumers() {
return consumers;
}
public void setConsumers(Set<Consumer> consumers) {
this.consumers = consumers;
}
public Commodity(){}
public Commodity(String commName, Float commPrice, String commVender) {
this.commName = commName;
this.commPrice = commPrice;
this.commVender = commVender;
}
public void addConsumer(Consumer consumer)
{
//向集合中添加数据 相当于向关联表中插入数据
this.consumers.add(consumer);
}
public void removeConsumer(Consumer consumer)
{
//因为hashset判断两个对象是否相等 使用的是equals方法 并且hashcode也要一样 才相等
//所以想要id标示一个consumer对象 必须要使用id重写equals与hashcode方法
if(this.consumers.contains(consumer))
this.consumers.remove(consumer);
}
}
顾客 Consumer.java
package com.undergrowth;
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;
@Entity
public class Consumer {
@Id @GeneratedValue
private Integer id;
@Column(length=20,nullable=false)
private String name;
@Column(nullable=false)
private Integer age;
@ManyToMany(mappedBy="consumers")
private Set<Commodity> commodities=new HashSet<Commodity>();
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;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Set<Commodity> getCommodities() {
return commodities;
}
public void setCommodities(Set<Commodity> commodities) {
this.commodities = commodities;
}
public Consumer(){}
public Consumer(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Consumer other = (Consumer) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
测试单元 JunitTest.java
package com.junit;
import static org.junit.Assert.*;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
public class JunitTest {
@Test
public void test() {
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
factory.close();
}
}
运行test 创建表结构 如下:
修改test函数 实现多对多的映射关系
package com.junit;
import static org.junit.Assert.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.undergrowth.Commodity;
import com.undergrowth.Consumer;
public class JunitTest {
@Test
public void test() {
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
EntityManager manager=factory.createEntityManager();
manager.getTransaction().begin();
manager.persist(new Commodity("lenovo笔记本", 5000f, "联想集团"));
manager.persist(new Consumer("under", 20));
manager.getTransaction().commit();
manager.close();
factory.close();
}
}
以上修改只是向commodity和consumer中添加了记录 但是两者之间的关系 还是没有建立 因此我们还需要手动的建立两者间的关系
oracle效果如下:
建立两个表之间的多对多的关系 添加建立关系函数 如下:
package com.junit;
import static org.junit.Assert.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.undergrowth.Commodity;
import com.undergrowth.Consumer;
public class JunitTest {
@Test
public void test() {
EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
EntityManager manager=factory.createEntityManager();
manager.getTransaction().begin();
Commodity cmoCommodity1=new Commodity("lenovo笔记本", 5000f, "联想集团");
Commodity cmoCommodity2=new Commodity("hp笔记本", 4500f, "hp集团");
Consumer consumer1=new Consumer("under", 20);
Consumer consumer2=new Consumer("刘德华", 25);
manager.persist(cmoCommodity1);
manager.persist(cmoCommodity2);
manager.persist(consumer1);
manager.persist(consumer2);
buildCC(cmoCommodity1,consumer1);
buildCC(cmoCommodity1,consumer2);
buildCC(cmoCommodity2,consumer2);
manager.getTransaction().commit();
manager.close();
factory.close();
}
//建立表间关系 实质上是在向关联表中添加记录
public void buildCC(Commodity cmoCommodity,Consumer consumer)
{
cmoCommodity.addConsumer(consumer);
}
}
上面即是建立了多对多的关系 一个顾客可以买多种商品 一种商品也可以被多个可以购买
控制台输出:
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into Commodity (commName, commPrice, commVender, id) values (?, ?, ?, ?)
Hibernate: insert into Commodity (commName, commPrice, commVender, id) values (?, ?, ?, ?)
Hibernate: insert into Consumer (age, name, id) values (?, ?, ?)
Hibernate: insert into Consumer (age, name, id) values (?, ?, ?)
Hibernate: insert into comm_consu (comm_id, consu_id) values (?, ?)
Hibernate: insert into comm_consu (comm_id, consu_id) values (?, ?)
Hibernate: insert into comm_consu (comm_id, consu_id) values (?, ?)
oracle效果:
以上即是jpa中对象之间的三种关系实现