级联关系
关联关系
集合关系
继承关系
Node树形节点
级联关系
1. CascadeType.PERSIST:级联新增(又称级联保存):对order对象保存时也对items里的对象也会保存。对应EntityManager的presist方法
例子:只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)
2. CascadeType.MERGE:级联合并(级联更新):若items属性修改了那么order对象保存时同时修改items里的对象。对应EntityManager的merge方法
例子:指A类新增或者变化,会级联B对象(新增或者变化)
3. CascadeType.REMOVE:级联删除:对order对象删除也对items里的对象也会删除。对应EntityManager的remove方法
例子:REMOVE只有A类删除时,会级联删除B类;
4. CascadeType.REFRESH:级联刷新:获取order对象里也同时也重新获取最新的items时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据 (用的比较少)
5. CascadeType.ALL:以上四种都是
综上所述:一般的,用CascadeType.MERGE:级联合并(级联更新)就能达到级更新同时又稳定不报错。
一 Hibernate关联关系
@JoinColumn:在a主表外键name=“b_id”(不写name默认是b_id)连接从表b的id
关联关系 | 数据库表 | 主类 | 持久类 | 测试类 | 说明 |
一对一单向主键 |
|
|
|
| 一个丈夫只有一个妻子 |
一对一双向主键 | 同一对一单向主键 | 同一对一单向主键 |
比一对一单向主键多:
Husband字段
@OneToOne
@PrimaryKeyJoinColumn
|
| 一个丈夫只有一个妻子 |
一对一单向外键 |
|
|
|
| 一个丈夫只有一个妻子 |
一对一双向外键 | 同一对一单向主键 | 同一对一单向主键 |
比一对一单向主键多:
Husband字段
@OneToOne
(
mappedBy
=
"wife"
)
|
| 一个丈夫只有一个妻子 |
单向多对一 |
|
|
|
| 多个用户在一个组 |
单向一对多 | 同多对一单向 |
JoinColumn实际是上在主的一方,外键连接从的表,但是在一对多时,需要JoinColumn在从表中标识,实际上还是在主表外键连接从表的作用
|
|
| 一个组有多个用户 |
双向一对多等于多对一 | 同多对一单向 |
|
|
| 一个组有多个用户 |
单向多对多 |
|
|
|
| 一个学生有多个老师,一个老师教多个学生 |
双向多对多 | 同单向多对多 | 同单向多对多 |
比一对一单向主键多:
Set
<
Teacher
>
teachers
字段
@OneToOne
(
mappedBy
=
"wife"
)
|
| 一个学生有多个老师,一个老师教多个学生 |
组件映射 |
|
|
|
| 一个类的属性是另一个类,或者两个类有相同字段,抽象出一个实体独享类 |
复合主键
多个字段构成唯一性
复合主键的映射:一般情况把主键相关的属性抽取出来单独放入一个类中。
必须实现序列化接口:重写hashCode(),equals()
数据库表
CREATE TABLE `comprimary` (
`p_id` int(11) NOT NULL,
`p_date` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`p_id`,`p_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复合主键类需要实现Serializable的hashCode(),equals()方法
复合主键类方法 | 复合主键类 | 实体类 | 测试 |
将主键类注解为@Embeddable,并将主键的属性注解为@Id |
|
| |
将组件的属性注解为@EmbeddedId 复合主键类不需要任何注解 | 复合主键类不需要任何注解 |
|
|
在实体类添加注解@IdClass,并将该实体中所有属于复合主键类的属性都注解为@Id | 复合主键类不需要任何注解 |
|
|
二. 集合映射(com.liuhao.hibernate4.demo.set_list_map)
数据库表结构都是一样的
使用的是双向多对一关系
CREATE TABLE `t_group` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`group_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_e5f24mh6aryt9hsy99oydps6g` (`group_id`),
CONSTRAINT `FK_e5f24mh6aryt9hsy99oydps6g` FOREIGN KEY (`group_id`) REFERENCES `t_group` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
集合类型 | 一的一端 | 多的一端 | 测试 |
Set |
|
|
|
List | List和Set没有区别将Set改成List
|
|
|
Map | Map是将Set改成Map,同时添加一个@Mapkey(value="id")指定map中key对应字段
|
|
|
三. 继承映射(com.liuhao.hibernate4.demo.inherit)
继承映射:就是把类的继承关系映射到数据库里(首先正确的存储,再正确的加载数据)
(一) 继承关联映射的分类:
1. 单表继承:每棵类继承树使用一个表(table per class hierarchy)
2. 具体表继承:每个子类一个表(table per subclass)
3. 类表继承:每个具体类一个表(table per concrete class)(有一些限制)
实例环境:动物Animal有三个基本属性,然后有一个Pig继承了它并扩展了一个属性,还有一个Brid也继承了并且扩展了一个属性
对象模型:
(二) 单表继承SINGLE_TABLE:
每棵类继承树使用同一个表
把所有的属性都要存储表中,目前至少需要5个字段,另外需要加入一个标识字段(表示哪个具体的子类)
animal
①、id:表主键
②、name:动物的姓名,所有的动物都有
③、sex:动物的性别,所有的动物都有
④、weight:猪(Pig)的重量,只有猪才有,所以鸟就没有重量数据
⑤、height:鸟(height)的调试,只有鸟才有,所以猪猪就没有高度数据
⑥、type:表示动物的类型;P表示猪;B表示鸟
注解实体类:
父类:
//@Inheritance 表示继承关系 SINGLE.TABLE单表继承
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
//DiscriminatorColumn 区别的字段和类型(用于数据库表创建)
@DiscriminatorColumn(name="type",
discriminatorType=DiscriminatorType.STRING)
//DiscriminatorValue 当前类使用的区别标示值
@DiscriminatorValue(value = "animal")
Animal
package com.liuhao.hibernate4.demo.inherit.singletable;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import org.apache.commons.lang3.builder.ToStringBuilder;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type",
discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue(value = "animal")
public class Animal {
private int id;
private String name;
private boolean sex;
public Animal(){};
public Animal(int id, String name, boolean sex) {
super();
this.id = id;
this.name = name;
this.sex = sex;
}
@Id
@GeneratedValue
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 boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("id", id);
builder.append("name", name);
builder.append("sex", sex);
return builder.toString();
}
}
子类:
只需要
//DiscriminatorValue 子类使用的区别标示值
@DiscriminatorValue(value = "xxx")
Pig
package com.liuhao.hibernate4.demo.inherit.singletable;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
@Entity
@DiscriminatorValue(value = "pig")
public class Pig extends Animal {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("weight", weight);
return builder.toString();
}
}
Bird
package com.liuhao.hibernate4.demo.inherit.singletable;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
@Entity
@DiscriminatorValue(value = "bird")
public class Bird extends Animal {
private int height;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("height", height);
return builder.toString();
}
}
导出数据库表:
CREATE TABLE `animal` (
`type` varchar(31) NOT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`sex` bit(1) NOT NULL,
`weight` int(11) DEFAULT NULL,
`height` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
测试类:
1. 插入父类,子类数据
/**
* singtable 单表继承
*/
@Test
public void testSingTable() {
session.beginTransaction();
Animal al = new Animal();
al.setName("al1");
al.setSex(true);
Pig p1 = new Pig();
p1.setName("p1");
p1.setSex(true);
p1.setWeight(200);
Bird b1 = new Bird();
b1.setName("b1");
b1.setSex(false);
b1.setHeight(30);
session.saveOrUpdate(al);
session.saveOrUpdate(p1);
session.saveOrUpdate(b1);
log.debug("Animal " + al);
log.debug("Pig extends Animal" + p1);
log.debug("Bird extends Animal" + b1);
session.flush();
session.getTransaction().commit();
}
控制台输出:
Hibernate:
insert
into
Animal
(name, sex, type)
values
(?, ?, 'animal')
//type被标识为 animal , 没有height , weightHibernate:
insert
into
Animal
(name, sex, weight, type)
values
(?, ?, ?, 'pig')
//type被标识为 pig , 没有weightHibernate:
insert
into
Animal
(name, sex, height, type)
values
(?, ?, ?, 'bird')
//type被标识为 bird , 没有height2015-07-02 10:06:19,725 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.singletable.Animal@61cd2[id=1,name=al1,sex=true]
2015-07-02 10:06:19,725 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Pig extends Animalcom.liuhao.hibernate4.demo.inherit.singletable.Pig@1469658[weight=200]
2015-07-02 10:06:19,725 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Bird extends Animalcom.liuhao.hibernate4.demo.inherit.singletable.Bird@1dafb4e[height=30]
执行后:
2. 加载父类
/**
* singtable 单表继承 加载父类
*/
@Test
public void testSuper() {
session.beginTransaction();
Animal al = (Animal) session.load(Animal.class, 1);
log.debug("Animal " + al);
session.flush();
session.getTransaction().commit();
}
控制台输出:
Hibernate:
select
animal0_.id as id2_0_0_,
animal0_.name as name3_0_0_,
animal0_.sex as sex4_0_0_,
animal0_.weight as weight5_0_0_,
animal0_.height as height6_0_0_,
animal0_.type as type1_0_0_
from
Animal animal0_
where
animal0_.id=?
//注:因为使用父类加载数据,所以hibernate会将所有字段(height、weight、type)的数据全部加载,并且条件中没有识别字段type(也就不区分什么子类,把所有子类全部加载上来?。)
2015-07-02 10:10:41,843 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.singletable.Animal@1c8b24d[id=1,name=al1,sex=true]
3. 加载子类
package com.liuhao.hibernate4.demo.uril;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class HibernateUtil {
private static final SessionFactory sessionFactory = createSessionFactory();
private HibernateUtil() {
}
private static SessionFactory createSessionFactory() {
SessionFactory sf = null;
try {
Configuration cfg = new Configuration();
cfg.configure(); // 重要,表示执行默认的hibernate.cfg.xml配置文件
ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(
cfg.getProperties()).buildServiceRegistry();
sf = cfg.buildSessionFactory(sr);
} catch (Exception e) {
e.printStackTrace();
}
return sf;
}
public synchronized static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
控制台输出:
Hibernate:
select
pig0_.id as id2_0_0_,
pig0_.name as name3_0_0_,
pig0_.sex as sex4_0_0_,
pig0_.weight as weight5_0_0_
from
Animal pig0_
where
pig0_.id=?
and pig0_.type='pig'
// type = 'pig'自动确定类型,且只加载子类的字段
2015-07-02 10:13:02,691 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Pig com.liuhao.hibernate4.demo.inherit.singletable.Pig@1de4dd8[weight=200]
Hibernate:
select
bird0_.id as id2_0_0_,
bird0_.name as name3_0_0_,
bird0_.sex as sex4_0_0_,
bird0_.height as height6_0_0_
from
Animal bird0_
where
bird0_.id=?
and bird0_.type='bird'
// type = 'bird'自动确定类型,且只加载子类的字段
2015-07-02 10:13:02,756 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Bird com.liuhao.hibernate4.demo.inherit.singletable.Bird@15c97e4[height=30]
4. 多态查询
4.1 load方法
load是延迟加载,返回代理对象
select查询受load入参类型影响
返回的持久化实例
不受数据库查询主键标识得到行type类型影响,
受load入参类型影响
解决办法:
lazy=false 修改成非延迟加载
/**
* singtable 单表继承
* 多态查询 load不支持多态查询,
* 因为load延迟加载不支持多态查询返回的是load(Object.class,id)的Object代理对象
* 数据库 id=2 是一个type='pig'对象
*
-------------------------------------
load(Animal.class, 2) -->返回Animal
输出结果: 没有对字段区分
是动物
Hibernate:
select
animal0_.id as id2_0_0_,
animal0_.name as name3_0_0_,
animal0_.sex as sex4_0_0_,
animal0_.weight as weight5_0_0_,
animal0_.height as height6_0_0_,
animal0_.type as type1_0_0_
from
Animal animal0_
where
animal0_.id=?
2015-07-02 10:40:06,100 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.singletable.Pig@1de4dd8[weight=200]
-------------------------------------
load(Pig.class, 2) -->返回Pig
输出结果:对字段区分
是猪
Hibernate:
select
pig0_.id as id2_0_0_,
pig0_.name as name3_0_0_,
pig0_.sex as sex4_0_0_,
pig0_.weight as weight5_0_0_
from
Animal pig0_
where
pig0_.id=?
and pig0_.type='pig'
2015-07-02 10:32:03,744 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.singletable.Pig@1de4dd8[weight=200]
-------------------------------------
-------------------------------------
load(Bird.class, 2) -->返回Bird
输出结果:报错字段不匹配插入不进去
是鸟
Hibernate:
select
bird0_.id as id2_0_0_,
bird0_.name as name3_0_0_,
bird0_.sex as sex4_0_0_,
bird0_.height as height6_0_0_
from
Animal bird0_
where
bird0_.id=?
and bird0_.type='bird'
* 结论:
* load是延迟加载
* select查询受load入参类型影响
* 返回的持久化实例
* 不受数据库查询主键标识得到行type类型影响,
* 受load入参类型影响
* 解决办法:
* lazy=false 修改成非延迟加载
*/
@Test
public void testMulti_load() {
session.beginTransaction();
// id=2 是一个pig 因为lazy=true(false支持多态查询) load不支持多态查询 所以返回的是一个Animal的子类
Animal al = (Animal) session.load(Animal.class, 2);
//Animal al = (Animal) session.load(Pig.class, 2);
//Animal al = (Animal) session.load(Bird.class, 2);
if (al instanceof Pig) {
System.out.println("是猪");
} else if(al instanceof Bird){
System.out.println("是鸟");
} else if(al instanceof Animal){
System.out.println("是动物");
} else{
System.out.println("是未知生物");
}
log.debug("Animal " + al);
session.flush();
session.getTransaction().commit();
}
4.2 get方法
get方法select查询受get入参影响,
但是返回持久化实例受数据库查询主键标识得到行type类型影响
/**
* singtable 单表继承
* 多态查询
* get 支持多态查询
* 数据库 id=2 是一个type='pig'对象
* get是直接加载
*
* ---------------------------------------------
* 即使get(Animal.class, 2) 返回的也是一个Pig对象
*
* 控制台输出: 返回结果正确,查询条件没有区分type
* Hibernate:
select
animal0_.id as id2_0_0_,
animal0_.name as name3_0_0_,
animal0_.sex as sex4_0_0_,
animal0_.weight as weight5_0_0_,
animal0_.height as height6_0_0_,
animal0_.type as type1_0_0_
from
Animal animal0_
where
animal0_.id=?
是猪
2015-07-02 10:44:42,273 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.singletable.Pig@1de4dd8[weight=200]
---------------------------------------------
get(Pig.class, 2) 返回的也是一个Pig对象
控制台输出: type有区分,返回结果也正确
Hibernate:
select
pig0_.id as id2_0_0_,
pig0_.name as name3_0_0_,
pig0_.sex as sex4_0_0_,
pig0_.weight as weight5_0_0_
from
Animal pig0_
where
pig0_.id=?
and pig0_.type='pig'
是猪
2015-07-02 10:48:35,202 [com.liuhao.hibernate4.demo.inherit.test.InheritTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.singletable.Pig@156b386[weight=200]
*
* 总结:
* get方法select查询受get入参影响,
* 但是返回持久化实例受数据库查询主键标识得到行type类型影响
*/
@Test
public void testMulti_get() {
session.beginTransaction();
//Animal al = (Animal) session.get(Animal.class, 2);
Animal al = (Animal) session.get(Pig.class, 2);
if (al instanceof Pig) {
System.out.println("是猪");
} else if(al instanceof Bird){
System.out.println("是鸟");
} else if(al instanceof Animal){
System.out.println("是动物");
} else{
System.out.println("是未知生物");
}
log.debug("Animal " + al);
session.flush();
session.getTransaction().commit();
}
4.3 HQL查询
/**
* singtable 单表继承 HQL支持多态查询
*/
@Test
public void testMulti_HQL() {
System.out.println("========================");
session.beginTransaction();
// HQL支持多态查询
List list = session.createQuery("from Animal").list();
for (Iterator it = list.iterator(); it.hasNext();) {
Animal al = (Animal) it.next();
if (al instanceof Pig) {
System.out.println("是猪");
} else if(al instanceof Bird){
System.out.println("是鸟");
} else if(al instanceof Animal){
System.out.println("是动物");
} else{
System.out.println("是未知生物");
}
log.debug("Animal " + al);
}
session.flush();
session.getTransaction().commit();
System.out.println("========================");
}
4.4 HQL查询hibernate.cfg.xml映射所有表
/**
* singtable 单表继承
* HQL查询所有表中所有的实体对象
*/
@Test
public void testMulti_HQLALL() {
System.out.println("========================");
session.beginTransaction();
// HQL支持多态查询
List list = session.createQuery("from java.lang.Object").list();
for (Iterator it = list.iterator(); it.hasNext();) {
Object obj = it.next();
if (obj instanceof Pig) {
System.out.println("是猪");
} else if(obj instanceof Bird){
System.out.println("是鸟");
} else if(obj instanceof Animal){
System.out.println("是动物");
} else{
System.out.println("是未知生物");
}
log.debug("Object " + obj);
}
session.flush();
session.getTransaction().commit();
System.out.println("========================");
}
(三) 具体表继承JOINED(com.liuhao.hibernate4.demo.inherit.joined):
每个类映射成一个表(table per subclass)
对象模型不用变化,存储模型需要变化
关系模型:
每个类映射成一个表(table per subclass)
注:因为需要每个类都映射成一张表,所以Animal也映射成一张表(animal),表中字段为实体类属性
而pig子类也需要映射成一张表(pid),但为了与父类联系需要加入一个外键(pidid)指向父类映射成的表(animal),字段为子类的扩展属性。
Bird子类同样也映射成一张表(bird),也加入一个外键(birdid)指向父类映射成的表(animal),字段为子类的扩展属性。
父类
Animal
package com.liuhao.hibernate4.demo.inherit.joined;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author liuhao
* @com.liuhao.hibernate4.demo.inherit.singletable
* @Animal.java
* @2015年7月2日 @下午2:38:21
* @version
* @comments 具体表继承父类
*/
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Animal {
private int id;
private String name;
private boolean sex;
public Animal(){};
public Animal(int id, String name, boolean sex) {
super();
this.id = id;
this.name = name;
this.sex = sex;
}
@Id
@GeneratedValue
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 boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("id", id);
builder.append("name", name);
builder.append("sex", sex);
return builder.toString();
}
}
子类:
Bird
package com.liuhao.hibernate4.demo.inherit.joined;
import javax.persistence.Entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author liuhao
* @com.liuhao.hibernate4.demo.inherit.singletable
* @Bird.java
* @2015年7月2日 @下午2:38:34
* @version
* @comments 具体表继承子类
*/
@Entity
public class Bird extends Animal {
private int height;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("height", height);
return builder.toString();
}
}
Pig
package com.liuhao.hibernate4.demo.inherit.joined;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author liuhao
* @com.liuhao.hibernate4.demo.inherit.singletable
* @Pig.java
* @2015年7月2日 @下午2:38:49
* @version
* @comments 具体表继承子类
*/
@Entity
public class Pig extends Animal {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("weight", weight);
return builder.toString();
}
}
导出数据库表
CREATE TABLE `animal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`sex` bit(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
CREATE TABLE `bird` (
`height` int(11) NOT NULL,
`id` int(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_98gbwudq8mjdefuqcd1tvsb09` FOREIGN KEY (`id`) REFERENCES `animal` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `pig` (
`weight` int(11) NOT NULL,
`id` int(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_fls50krk7jm94r9lb2edpwqmd` FOREIGN KEY (`id`) REFERENCES `animal` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Animal
Bird
Pig
1. 数据插入
/**
* 数据插入
*
* 子类插入行,都会在父类先插入对应数据
* 控制台输出:
*
* ===========insert===========
Hibernate:
insert
into
Animal
(name, sex)
values
(?, ?)
Hibernate:
insert
into
Animal
(name, sex)
values
(?, ?)
Hibernate:
insert
into
Pig
(weight, id)
values
(?, ?)
Hibernate:
insert
into
Animal
(name, sex)
values
(?, ?)
Hibernate:
insert
into
Bird
(height, id)
values
(?, ?)
2015-07-02 14:59:00,717 [com.liuhao.hibernate4.demo.inherit.test.InheritJoinedTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.joined.Animal@5dfaf1[id=5,name=老虎,sex=true]
2015-07-02 14:59:00,717 [com.liuhao.hibernate4.demo.inherit.test.InheritJoinedTest]-[DEBUG] Pig com.liuhao.hibernate4.demo.inherit.joined.Pig@159e6e8[weight=200]
2015-07-02 14:59:00,717 [com.liuhao.hibernate4.demo.inherit.test.InheritJoinedTest]-[DEBUG] Bird com.liuhao.hibernate4.demo.inherit.joined.Bird@a6af6e[height=30]
===========insert end===========
*/
@Test
public void testInsert() {
System.out.println("===========insert===========");
session.beginTransaction();
Animal animal = new Animal();
animal.setName("老虎");
animal.setSex(true);
Pig pig = new Pig();
pig.setName("猪");
pig.setSex(true);
pig.setWeight(200);
Bird bird = new Bird();
bird.setName("鸟");
bird.setSex(false);
bird.setHeight(30);
session.saveOrUpdate(animal);
session.saveOrUpdate(pig);
session.saveOrUpdate(bird);
session.flush();
session.getTransaction().commit();
log.debug("Animal " + animal);
log.debug("Pig " + pig);
log.debug("Bird " + bird);
System.out.println("===========insert end===========");
}
2. 数据加载
/**
* 数据插入
*
* 子类插入行,都会在父类先插入对应数据
* 控制台输出:
* ===========Get===========
Hibernate:
select
animal0_.id as id1_0_0_,
animal0_.name as name2_0_0_,
animal0_.sex as sex3_0_0_,
animal0_1_.weight as weight1_2_0_,
animal0_2_.height as height1_1_0_,
case
when animal0_1_.id is not null then 1
when animal0_2_.id is not null then 2
when animal0_.id is not null then 0
end as clazz_0_
from
Animal animal0_
left outer join
Pig animal0_1_
on animal0_.id=animal0_1_.id
left outer join
Bird animal0_2_
on animal0_.id=animal0_2_.id
where
animal0_.id=?
Hibernate:
select
pig0_.id as id1_0_0_,
pig0_1_.name as name2_0_0_,
pig0_1_.sex as sex3_0_0_,
pig0_.weight as weight1_2_0_
from
Pig pig0_
inner join
Animal pig0_1_
on pig0_.id=pig0_1_.id
where
pig0_.id=?
Hibernate:
select
bird0_.id as id1_0_0_,
bird0_1_.name as name2_0_0_,
bird0_1_.sex as sex3_0_0_,
bird0_.height as height1_1_0_
from
Bird bird0_
inner join
Animal bird0_1_
on bird0_.id=bird0_1_.id
where
bird0_.id=?
2015-07-02 15:03:50,149 [com.liuhao.hibernate4.demo.inherit.test.InheritJoinedTest]-[DEBUG] Animal com.liuhao.hibernate4.demo.inherit.joined.Animal@9b1670[id=5,name=老虎,sex=true]
2015-07-02 15:03:50,150 [com.liuhao.hibernate4.demo.inherit.test.InheritJoinedTest]-[DEBUG] Pig com.liuhao.hibernate4.demo.inherit.joined.Pig@58dd2d[weight=200]
2015-07-02 15:03:50,150 [com.liuhao.hibernate4.demo.inherit.test.InheritJoinedTest]-[DEBUG] Bird com.liuhao.hibernate4.demo.inherit.joined.Bird@159e6e8[height=30]
===========Get end===========
*/
@Test
public void testGet() {
System.out.println("===========Get===========");
session.beginTransaction();
Animal animal = (Animal) session.get(Animal.class, 5);
Pig pig = (Pig) session.get(Pig.class, 6);
Bird bird = (Bird) session.get(Bird.class, 7);
session.flush();
session.getTransaction().commit();
log.debug("Animal " + animal);
log.debug("Pig " + pig);
log.debug("Bird " + bird);
System.out.println("===========Get end===========");
}
单表继承和具体表区别?
1. 单表继承效率高,但是有多余字段
2. 具体表结构分明
(四)类表继承(com.liuhao.hibernate4.demo.table_per_class)
每个具体类映射成一个表(table per concreteclass)(有一些限制)
对象模型不用变化,存储模型需要变化
1. 关系模型:
每个具体类(Pig、Brid)映射成一个表(table per concrete class)(有一些限制)
实体类:
Animal
因为子类表的ID是不可以重复,所以一般的主键生成策略已经不适应了,只有表主键生成策略。
因为父类表没有任何作用 所以将此类设置为abstract
package com.liuhao.hibernate4.demo.inherit.table_per_class;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.TableGenerator;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author liuhao
* @com.liuhao.hibernate4.demo.inherit.singletable
* @Animal.java
* @2015年7月2日 @下午2:38:21
* @version
* @comments 类表继承 父类
*/
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@TableGenerator(
name="t_generator",
table="t_table",
pkColumnName="t_pk",
valueColumnName="t_value",
pkColumnValue="id_pk",
initialValue=1,
allocationSize=1
)
public abstract class Animal {
private int id;
private String name;
private boolean sex;
public Animal(){};
public Animal(int id, String name, boolean sex) {
super();
this.id = id;
this.name = name;
this.sex = sex;
}
@Id
@GeneratedValue(generator="t_generator",strategy=GenerationType.TABLE)
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 boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("id", id);
builder.append("name", name);
builder.append("sex", sex);
return builder.toString();
}
}
Bird
package com.liuhao.hibernate4.demo.inherit.table_per_class;
import javax.persistence.Entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author liuhao
* @com.liuhao.hibernate4.demo.inherit.singletable
* @Bird.java
* @2015年7月2日 @下午2:38:34
* @version
* @comments 类表继承 子类
*/
@Entity
public class Bird extends Animal {
private int height;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("height", height);
return builder.toString();
}
}
Pig
package com.liuhao.hibernate4.demo.inherit.table_per_class;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author liuhao
* @com.liuhao.hibernate4.demo.inherit.singletable
* @Pig.java
* @2015年7月2日 @下午2:38:49
* @version
* @comments 类表继承 子类
*/
@Entity
public class Pig extends Animal {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("weight", weight);
return builder.toString();
}
}
导出数据库表:
CREATE TABLE `bird` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`sex` bit(1) NOT NULL,
`height` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `pig` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`sex` bit(1) NOT NULL,
`weight` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
BIrd表
Pig表
Table主键策略表
初始化为2 因为一开始执行一次
Insert和Get操作
/**
* Table_Per_Class 类表继承
*
* 控制台输出:
* Table_Per_Class只能使用table主键生成策略,
* 所以每次insert都会select table主键生成表 再update此表
* 最后insert到当前表中
*/
@Test
public void testInsert() {
System.out.println("===========Insert===========");
session.beginTransaction();
Pig p1 = new Pig();
p1.setName("p1");
p1.setSex(true);
p1.setWeight(200);
Bird b1 = new Bird();
b1.setName("b1");
b1.setSex(false);
b1.setHeight(30);
session.saveOrUpdate(p1);
session.saveOrUpdate(b1);
log.debug("Pig extends Animal" + p1);
log.debug("Bird extends Animal" + b1);
session.flush();
session.getTransaction().commit();
System.out.println("===========Insert End===========");
}
@Test
public void testGet() {
System.out.println("===========Get===========");
session.beginTransaction();
Pig pig = (Pig) session.get(Pig.class, 3);
Bird bird = (Bird) session.get(Bird.class, 4);
session.flush();
session.getTransaction().commit();
log.debug("Pig " + pig);
log.debug("Bird " + bird);
System.out.println("===========Get end===========");
}
总结:
三种继承
第一种:它把所有的数据都存入一个表中,优点:效率好(操作的就是一个表);缺点:存在庸于字段,如果将庸于字段设置为非空,则就无法存入数据;
第二种:层次分明,缺点:效率不好(表间存在关联表)
第三种:主键字段不可以设置为自增主键生成策略。
一般使用第一种
继承类型 | 数据库表 | 父类 | 子类 |
single table 单表 |
|
|
|
joined 具体表继承 |
Animal
Bird
Pig
|
|
|
类表继承 |
BIrd表
Pig表
Table主键策略表
初始化为2 因为一开始执行一次
|
|
|
(五)树形结构(comliuhao.demo.node)
Node
package com.liuhao.hibernate4.demo.node;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.apache.commons.lang3.builder.ToStringBuilder;
@Entity
public class Node {
private int id; // 标识符
private String name; // 节点名称
private int level; // 层次,为了输出设计
private boolean leaf; // 是否为叶子节点,这是为了效率设计,可有可无
// 父节点:因为多个节点属于一个父节点,因此用hibernate映射关系说是“多对一”
private Node parent;
// 子节点:因为一个节点有多个子节点,因此用hibernate映射关系说是“一对多”
private Set<Node> children = new HashSet<Node>();
@Id
@GeneratedValue
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 int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public boolean isLeaf() {
return leaf;
}
public void setLeaf(boolean leaf) {
this.leaf = leaf;
}
@ManyToOne
@JoinColumn(name="pid")
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
@OneToMany(mappedBy = "parent")
public Set<Node> getChildren() {
return children;
}
public void setChildren(Set<Node> children) {
this.children = children;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("id", id);
builder.append("name", name);
builder.append("level", level);
builder.append("leaf", leaf);
builder.append("parent", parent);
builder.append("children", children);
return builder.toString();
}
}
测试类
@Test
public void testInsert(){
System.out.println("==========================");
session.beginTransaction();
Node root = new Node();
root.setName("root");
Node n1 = new Node();
n1.setName("n1");
Node n2 = new Node();
n2.setName("n2");
Node n11 = new Node();
n11.setName("n11");
Node n12 = new Node();
n12.setName("n12");
root.getChildren().add(n1);
root.getChildren().add(n2);
n1.getChildren().add(n11);
n1.getChildren().add(n12);
n11.setParent(n1);
n12.setParent(n1);
n1.setParent(root);
n2.setParent(root);
session.saveOrUpdate(root);
session.saveOrUpdate(n1);
session.saveOrUpdate(n2);
session.saveOrUpdate(n11);
session.saveOrUpdate(n12);
session.getTransaction().commit();
log.debug("root "+root);
log.debug("n1 "+n1);
log.debug("n2 "+n2);
log.debug("n11 "+n11);
log.debug("n12 "+n12);
System.out.println("==========================");
}
/**
* 导出
*/
@Test
public void testGet() {
System.out.println("==========================");
session.beginTransaction();
List list = session.createQuery("from Node").list();
for(Iterator it = list.iterator();it.hasNext();)
{
Node node = (Node) it.next();
System.out.println("Node :"+node);
}
session.getTransaction().commit();
System.out.println("==========================");
}
HibernateUtil
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/forum</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="connection.pool_size">10</property>
<mapping class="com.liuhao.hibernate4.demo.entity.User"></mapping>
<!-- 一对一单向主键 -->
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.primary.oneway.Person11pk"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.primary.oneway.Address11pk"></mapping>
<!-- 一对一双向主键 -->
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.primary.bothway.Wife"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.primary.bothway.Husband"></mapping>
<!-- 一对一单向外键 -->
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.foreign.oneway.IdCard"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.foreign.oneway.Person"></mapping>
<!-- 一对一双向外键 -->
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.foreign.bothway.Student"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.onetoone.foreign.bothway.StuIdCard"></mapping>
<!-- 联合主键 -->
<mapping class="com.liuhao.hibernate4.demo.entity.component.Employee"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.component.User"></mapping>
<!-- 多对一单向 -->
<mapping class="com.liuhao.hibernate4.demo.entity.manytoone.oneway.Group"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.manytoone.oneway.User"></mapping>
<!-- 多对一双向
<mapping class="com.liuhao.hibernate4.demo.entity.manytoone.bothway.Group"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.manytoone.bothway.User"></mapping>
-->
<!-- 多对多单向
<mapping class="com.liuhao.hibernate4.demo.entity.manytomany.oneway.Role"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.manytomany.oneway.User"></mapping>
-->
<!-- 多对多双向 -->
<mapping class="com.liuhao.hibernate4.demo.entity.manytomany.bothway.Role"></mapping>
<mapping class="com.liuhao.hibernate4.demo.entity.manytomany.bothway.User"></mapping>
<!-- 测试
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Husband_111p"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Wife_111p"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Husband_112p"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Wife_112p"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Husband_112f"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Wife_112f"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Husband_m12"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Wife_m12"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Husband_mm2"></mapping>
<mapping class="com.liuhao.hibernate4.demo.mappingtest.Wife_mm2"></mapping>
-->
</session-factory>
</hibernate-configuration>