Hibernate一对多关系操作
1、创建两个实体类。
一个实体类是商品类,另一个实体类是商品的分类类。
在一对多关系的两个实体中,在编写实体类时必须要遵循以下规则:
(1)在一的那一方的实体中,必须要有一个私有的多那一方的实体对象属性,并且提供公有的getter和setter方法。
private Integer gid;
private String gname;
private String gmessage;
/**
* 在一对多关系中,在一的这一方,必须要有一个多的对象的私有属性
* 别提供共有的getter和setter方法。
*/
private Sort sort;
public Sort getSort() {
return sort;
}
public void setSort(Sort sort) {
this.sort = sort;
}
(2)在多的那一方的实体类中,必须要有一个私有的set集合属性来保存一的那一方的对象,并提供公有的getter和setter属性。
private Integer sid;
private String gname;
private String gmessage;
/**
* 在一对多关系中,在多的那一方,必须要有一个set集合属性来保存一个那个实体
* 并提供共有的getter和setter方法。
*/
private Set<Good> getSet = new HashSet<Good>();
public Set<Good> getGetSet() {
return getSet;
}
public void setGetSet(Set<Good> getSet) {
this.getSet = getSet;
}
2、编写两个实体类的映射文件。
(1)一的那一方的映射文件。
在一的这一方,需要使用<many-to-one>标签来配置对应关系。
<hibernate-mapping>
<class name="com.jack.entity.Good" table="t_good">
<id name="gid" column="gid">
<generator class="native"></generator>
</id>
<property name="gname" column="gname"></property>
<property name="gmessage" column="gmessage"></property>
<!--
表示商品所属的分类
name属性的值:因为在Good商品实体中,用sort表示Sort实体类,所有这里写sort
class属性的值:sort类的全路径
column属性的值:外键的名称
-->
<many-to-one name="sort" class="com.jack.entity.Sort" column="gsid"></many-to-one>
</class>
</hibernate-mapping>
(2)多的那一方的映射文件。
在多的这一方,需要使用<set>标签来配置对应关系。
<hibernate-mapping>
<class name="com.jack.entity.Sort" table="t_sort">
<id name="sid" column="sid">
<generator class="native"></generator>
</id>
<property name="sname" column="sname"></property>
<property name="smessage" column="smessage"></property>
<!--
在多的这一边使用set标签来设置对应关系
name属性的值:因为在Sort中使用getSet保存good属性。
column属性的值:外键的名称,由于在Hibernate使用双向维护主键
所有在这边的column的值必须要和另一边的值一致
class属性的值:Good实体类的全路径。
-->
<set name="getSet">
<key column="gsid"></key>
<one-to-many class="com.jack.entity.Good" />
</set>
</class>
</hibernate-mapping>
3、编写核心配置文件
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernatetest</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name=" hibernate.current_session_context_class">thread</property>
<mapping resource="com/jack/entity/Good.hbm.xml"/>
<mapping resource="com/jack/entity/Sort.hbm.xml"/>
</session-factory>
</hibernate-configuration>
4、编写工具类
public class HibernateUtils {
private static Configuration configuration = null;
private static SessionFactory sessionFactory = null;
static{
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
public static Session getSeeion() {
return sessionFactory.getCurrentSession();
}
}
5、编写级联保存代码
第一种代码(复杂):
@Test
public void TestAdd(){
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSeeion();
tx = session.beginTransaction();
/**
* 创建两个商品
*/
Good good1 = new Good();
good1.setGname("蛋糕");
good1.setGmessage("奶油蛋糕");
Good good2 =new Good();
good2.setGname("牙膏");
good2.setGmessage("冷酸灵牙膏");
/**
* 创建两个类别
*/
Sort sort1 =new Sort();
sort1.setSname("食品");
sort1.setSmessage("食品类");
Sort sort2 = new Sort();
sort2.setSname("生活用品");
sort2.setSmessage("生活用品类");
/**
* 将商品放到类别中
*/
sort1.getGetSet().add(good1);
sort2.getGetSet().add(good2);
/**
* 将类别设置到商品中
*/
good1.setSort(sort1);
good2.setSort(sort2);
/**
* 保存类别
* 保存商品
*/
session.save(sort1);
session.save(sort2);
session.save(good1);
session.save(good2);
tx.commit();
} catch (Exception e) {
tx.rollback();
}finally{
}
}
第二种代码(简单):
首先在多的那一方的配置文件的<set>标签内,写入cascade属性,其值为save-update。
<set name="getSet" cascade="save-update">
<key column="gsid"></key>
<one-to-many class="com.jack.entity.Good" />
</set>
然后编写代码
@Test
public void TestAdd2(){
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSeeion();
tx = session.beginTransaction();
/**
* 创建两个商品
*/
Good good3 = new Good();
good3.setGname("面包");
good3.setGmessage("面包");
/**
* 获得食品类
*/
Sort sort1 = session.get(Sort.class, 1);
/**
* 将商品放到类别中
*/
sort1.getGetSet().add(good3);
/**
* 保存类别
* 现在只需要保存类别,商品也会自动保存
*/
session.save(sort1);
tx.commit();
} catch (Exception e) {
tx.rollback();
}finally{
}
}
6、Hibernate默认双方都要维护主键,这样会降低效率,通过配置inverse属性可以让一方放弃维护主键,这样可以提高操作效率。一般让多的那一方放弃。
<!--
true:表示不维护
false:表示维护主键
默认为false,维护主键
-->
<set name="getSet" cascade="save-update" inverse="true">
<key column="gsid"></key>
<one-to-many class="com.jack.entity.Good" />
</set>
7、测试结果
8、级联删除
首先配置cascade属性,值为delete
<set name="getSet" cascade="save-update,delete" inverse="true">
<key column="gsid"></key>
<one-to-many class="com.jack.entity.Good" />
</set>
编写代码实现删除(删除食品类)
@Test
public void TestDelete(){
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSeeion();
tx = session.beginTransaction();
/**
* 找到食品类
*/
Sort sort = session.get(Sort.class, 1);
/**
删除食品类
*/
session.delete(sort);
tx.commit();
} catch (Exception e) {
tx.rollback();
}finally{
}
}
测试结果:
9、级联修改
修改前数据库
修改代码(把蛋糕放到生活用品中):
@Test
public void TestUpdate(){
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSeeion();
tx = session.beginTransaction();
/**
* 找到生活用品
*/
Sort sort = session.get(Sort.class, 2);
/**
* 找到蛋糕
*/
Good good =session.get(Good.class, 4);
/**
* 把蛋糕放到生活用品中去
*/
sort.getGetSet().add(good);
/**
* 把生活用品设置到蛋糕中去
*/
good.setSort(sort);
tx.commit();
} catch (Exception e) {
tx.rollback();
}finally{
}
}
修改之后结果:
JPA(Java Persistence API)通过注解或XML描述对象与关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA是一个规范,是一个标准,Hibernate是实现了这个标准的开源框架。
1、引入hibernate-jpa-2.0-api-1.0.0.Final.jar JPA规范对应的hibernate的jar包
2、修改配置文件hibernate.cfg.xml 的映射关系<Mapping class="">
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- thread:一个线程中使用一个。获取session会话时使用-->
<property name="current_session_context_class">thread</property>
<!-- 是否显示SQL语句,值为布尔型,默认false -->
<property name="hibernate.show_sql">true</property>
<!-- 是否格式化显示sql语句,让显示更美观,值为布尔型,默认false -->
<property name="hibernate.format_sql">false </property>
<!-- 自动建表
update:每次执行时,无表则建表,无列则建列,只增不减
create:每次启动的时候,删除原表,再次创建
create-drop:每次启动时创建新表,当显式关闭sessionFactory时,删除表
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 连接数据库 -->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/zxd_db</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">zxd</property>
<property name="hibernate.connection.password">123456</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 读取注解 -->
<mapping class="demo.entity.Book" />
</session-factory>
</hibernate-configuration>
3、实体配置
package demo.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* 注解实体配置
* JPA通过注解或XML描述对象与关系表的映射关系,并将运行期的实体对象持久化到数据库中。
* @author Don
* @date:日期:2017年4月19日 时间:上午10:43:00*
* @version 1.0
*/
//标注实体
@Entity
//实体对应的表名,自动建库(若不写name,则表名与实体名保持一致)
@Table(name="tb_book")
public class Book {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
//主键ID注解
private int id;
@Id
@GenericGenerator(name="pk_uuid",strategy="uuid")
@GeneratedValue(generator="pk_uuid")
//生成UUID的主键注解
private String uuid;
@Column
//列注解
private String name;
@Column
private double price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
}
4、数据库实务session创建
package demo.util;
import java.text.Annotation;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
public class HibernateUtil {
public static Session getCurrentSession() {
/*注解调用使用AnnotationConfiguration 对象创建*/
// 加载Hibernate配置信息,默认读取src下的hibernate.cfg.xml
Configuration cfg = new AnnotationConfiguration().configure();
// 也可以指定hibernate.cfg.xml 的路径加载
// Configuration cfg1 = new Configuration().configure(Path);
/*
* 应用程序从SessionFactory(会话工厂)里获得Session(会话)实例。它在多个应用线程间进行共享。
* 通常情况下,整个应用只有唯一的一个会话工厂,SessionFactory由Configuration对象创建,
* 每个Hibernate配置文件,实际上是对SessionFactory的配置
*/
// 试用配置信息构建sessionFactory
SessionFactory factory = cfg.buildSessionFactory();
Session session =factory.getCurrentSession();
return session;
}
}
5、测试建表和增删改查和XML配置映射一致
(一)、 一对一映射(主键关联)
Card实体类
View Code
Person实体类
View Code
(二)、一对一映射(唯一外键)
Card实体类
View Code
Person实体类
View Code
(三)、一对多映射
Classes实体类(课程)
package demo.entity;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
@Entity
@Table(name="ann_m2o_Classes")
public class Classes {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column
private String name;
@OneToMany(mappedBy="cal")
@Cascade(CascadeType.ALL)
//一对多关系配置(配置Student实体中的Class实体映射对象,设计级联关系)
private List<Student> list = new ArrayList<Student>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Student> getList() {
return list;
}
public void setList(List<Student> list) {
this.list = list;
}
}
Student实体类(学生)
package demo.entity;
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;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
@Entity
@Table(name="ann_m2o_Student")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column
private String name;
@ManyToOne
@JoinColumn(name="cid")
@Cascade(CascadeType.SAVE_UPDATE)
private Classes cal;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Classes getCal() {
return cal;
}
public void setCal(Classes cal) {
this.cal = cal;
}
}
(四)、多对多映射(中间表)
Course实体类(选课)
package demo.entity;
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;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.GenericGenerator;
/**
* 课程实体
* @author Don
* @date:日期:2017年4月11日 时间:下午2:25:45*
* @version 1.0
*/
@Entity
@Table(name="ann_m2m_Course")
public class Course {
@Id
@GenericGenerator(name="pk_key",strategy="uuid")
@GeneratedValue(generator="pk_key")
private String id;
@Column
private String name;
@ManyToMany
//级联关系
@Cascade(CascadeType.SAVE_UPDATE)
//中间表
@JoinTable(name="ann_m2m_stu_course",
//链接当前对象的Id
joinColumns={@JoinColumn(name="cid",referencedColumnName="id")},
//链接对方的表的Id
inverseJoinColumns={@JoinColumn(name="stuId",referencedColumnName="id")})
private Set<Student> stus = new HashSet<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStus() {
return stus;
}
public void setStus(Set<Student> stus) {
this.stus = stus;
}
public Course(){}
public Course(String name) {
this.setName(name);
}
}
Student实体类(选课人员)
package demo.entity;
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.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.GenericGenerator;
/**
* 学生实体
* @author Don
* @date:日期:2017年4月11日 时间:下午2:25:15*
* @version 1.0
*/
@Entity
@Table(name="ann_m2m_Student")
public class Student {
@Id
//生成UUID
@GenericGenerator(name="pk_key",strategy="uuid")
@GeneratedValue(generator="pk_key")
private String id;
@Column
private String name;
@ManyToMany
//级联关系
@Cascade(CascadeType.SAVE_UPDATE)
//中间表
@JoinTable(name="ann_m2m_stu_course",
//链接当前对象的Id
joinColumns={@JoinColumn(name="stuId",referencedColumnName="id")},
//链接对方的表的Id
inverseJoinColumns={@JoinColumn(name="cid",referencedColumnName="id")})
private Set<Course> cous=new HashSet<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Course> getCous() {
return cous;
}
public void setCous(Set<Course> cous) {
this.cous = cous;
}
public Student() {
}
public Student(String name) {
this.setName(name);
}
}