hibernate对象之间存在关系,
=-=================================================================
一对一(主键关联,和单向的外键关联)
①单向(主键,外键)Husband和Wife表,a,主键关联 b,外键关联(wife为parent) ,c,主键关联 d,外键关联(husband为parent)
一对一单向外键关联:
annotation:@oneToOne @JoinColumn(name="wifeId")
xml : <many-to-one unique="true"/>
一对一单向主键关联:annotation:@PrimaryKeyJoinColumn(name="id",referencedColumnName="id")
xml: <one-to-one name="stu" constrained="true"/>
②双向(主键,外键)
一对一双向外键关联:
annotation:在husband类中:@oneToOne
在wife类中:@OneToOne(mappedBy="wife")对方为主导,对于一对一双向外键关联必须写mappedBy
xml : <many-to-one name="stu" unique="true" column="stuid" not-null="true"/>
<one-to-one name="idCard
property-ref="stu"></one-to-one>
<generator class="foreign">
<param name="property">stu</param>
</generator>
一对一双向主键关联:
annotation:
@OneToOne
@PrimaryKeyJoinColumn(name="id",referencedColumnName="id")
@OneToOne(mappedBy="wife")
@PrimaryKeyJoinColumn(name="id",columnDefinition="id")
a ,Husband的id与wife的id相互关联 b,husband的外键wifeid和wife中husbandid
联合主键关联(不重要):
Annotation:
@OneToOne
@JoinColumns(
{
@JoinColumn(name="wifid",referencedColumnName="id"),
@JoinColumn(name="wifename",referencedColumnName="name")
}
)
③中间表 建立一张中间表
一对一(主键关联,和单向的外键关联)
①单向(主键,外键)Husband和Wife表,a,主键关联 b,外键关联(wife为parent) ,c,主键关联 d,外键关联(husband为parent)
一对一单向外键关联:
annotation:@oneToOne @JoinColumn(name="wifeId")
xml : <many-to-one unique="true"/>
一对一单向主键关联:annotation:@PrimaryKeyJoinColumn(name="id",referencedColumnName="id")
xml: <one-to-one name="stu" constrained="true"/>
②双向(主键,外键)
一对一双向外键关联:
annotation:在husband类中:@oneToOne
在wife类中:@OneToOne(mappedBy="wife")对方为主导,对于一对一双向外键关联必须写mappedBy
xml : <many-to-one name="stu" unique="true" column="stuid" not-null="true"/>
<one-to-one name="idCard
property-ref="stu"></one-to-one>
<generator class="foreign">
<param name="property">stu</param>
</generator>
一对一双向主键关联:
annotation:
@OneToOne
@PrimaryKeyJoinColumn(name="id",referencedColumnName="id")
@OneToOne(mappedBy="wife")
@PrimaryKeyJoinColumn(name="id",columnDefinition="id")
a ,Husband的id与wife的id相互关联 b,husband的外键wifeid和wife中husbandid
联合主键关联(不重要):
Annotation:
@OneToOne
@JoinColumns(
{
@JoinColumn(name="wifid",referencedColumnName="id"),
@JoinColumn(name="wifename",referencedColumnName="name")
}
)
③中间表 建立一张中间表
一对多
①单向:
annotation:在一的一方加集合(Set),这种处理方式,hibernate把它当做了多对多关系处理,在数据库中建立了一张关系表。
@OneToMany
@JoinColumn(name="groupid")
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
Xml:
<set name="users">
<key column="groupid"></key>
<one-to-many class="User"/>
</set>
②双向(多对一的双向关联,一对多的双向关联是一样的)
多对一:
①单向(manytoone的单向关联):在多的一方加外键。1NF,要有主键,列不可分;2NF联合主键不能存在部分依赖3NF不能存在传递依赖。设计原则:不能产生冗余。
annotation:@ManyToOne
xml:<many-to-one name="g" column="groupid"></many-to-one>
②双向:(多对一的双向关联,一对多的双向关联是一样的)
Annotation:@ManyToOne
xml:
<set name="aliases" table="person_aliases" order-by="lower(name) asc">
<key column="person"/>
<element column="name" type="string"/>
</set>
多对多
①单向
annotation: @ManyToMany
xml :
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
②双向:
Annotation:
/**
*ManyToMany指明多对多关系
*JoinTable生成中间表,name指定中间表的名字,joinColumns
*指定参考这张表的主键的中间表的属性名,inverseJoinColumns
*指定参考相关表的主键的中间表的属性名。
*
*/
@ManyToMany
@JoinTable(name="t_t",joinColumns={
@JoinColumn(name="t_id")
},inverseJoinColumns={@JoinColumn(name="s_id")})
@ManyToMany(mappedBy="students")
Xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xie.hibernate.modal" >
<class name="Teacher" table="t_teacher">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<set name="students" table="t_s">
<key column="t_id"></key>
<many-to-many column="s_id" class="Student"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xie.hibernate.modal" >
<class name="Student" table="t_student">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<set name="teachers" table="t_s" inverse="true">
<key column="s_id"/>
<many-to-many column="t_id" class="Teacher"/>
</set>
</class>
</hibernate-mapping>
=-=================================================================
该如何映射呢?有3中方式,反映在数据库表上:
Single table:Student和Teacher类的父类是Person类,用一张数据库表反应3个类的所有信息。这样设计的缺点是:表的信息反映了所有类的属性,造成大量的数据冗余。
Table per class:为每个类设计一张表,其缺点是:
Joined:用一张表存共有的字段,而其子类对应的表存其特有字段。优缺点:查询能提高效率,然而需要作表连接,当添加新的子类时,需要添加新的表。
=====================================继承关系的映射=====================================================
Annotation:
⑴sigle_table:
package com.xie.hibernate.modal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
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 javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.sun.xml.internal.bind.v2.runtime.Name;
@Entity
//指定继承映射的策略
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
//在数据库表中加上一个字段,用以区分是哪个子类,name表示表的字段名字,discriminatorType
//表示name字段的数据类型
@DiscriminatorColumn(name="dis",discriminatorType=DiscriminatorType.STRING)
//指定这个类存到数据库中用什么区分,value表明dis的值
@DiscriminatorValue(value="person")
public class Person {
private int id;
private String name;
@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;
}
}
package com.xie.hibernate.modal;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
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
@DiscriminatorValue("student")
public class Student extends Person {
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
package com.xie.hibernate.modal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@DiscriminatorValue("teacher")
public class Teacher extends Person{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
⑵table_per_class:
package com.xie.hibernate.modal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
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.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import com.sun.xml.internal.bind.v2.runtime.Name;
@Entity
//指定继承映射的策略
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@TableGenerator(
name="k_gen",
table="key_table",
pkColumnName="p_key",
pkColumnValue="p_value",
initialValue=1,
allocationSize=1
)
public class Person {
private int id;
private String name;
@Id
@GeneratedValue(generator="k_gen",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;
}
}
package com.xie.hibernate.modal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
public class Teacher extends Person{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
⑶joined:
package com.xie.hibernate.modal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
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.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import com.sun.xml.internal.bind.v2.runtime.Name;
@Entity
//指定继承映射的策略
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {
private int id;
private String name;
@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;
}
}
package com.xie.hibernate.modal;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
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 Student extends Person {
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
package com.xie.hibernate.modal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
public class Teacher extends Person{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
===============================hibernate n+1==========================
在多对一关系中,当我们需要查询多的一方对应的表的记录时,可以用一条sql语句就能完成操作。然而,在多的一方的实体类中的@ManyToOne标注的fetch的默认值是eager,这时,hibernate除了发出查询多的一方对应的表的记录的sql语句外,还会发出n(多方记录数)条sql语句,这就是1+n问题。如:bbs的板块(Category),主题(topic),回复(msg)。一个板块有多个主题,而一个主题属于一个板块,则Category和topic属于一对多的关系,在topic里设置@ManyToOne。当需要取出所有的主题时,只需要发出select * from topic一条语句就能做到。然而,hibernate会查询出每个topic所对应的Category,所以会发出1+n条sql语句。
解决的方法是:①设置@ManyToOne的fetch属性值为lasy,这种方式解决后,后面的n条sql语句按需而发。
②设置@BatchSize(size=5),这样发出的sql语句减少。这个设置在一定程度上提高了效率。
③用join fetch,事实上Criteria用的就是这种方法。
//join fetch
@Test
public void test1_N3(){
Session session=sf.getCurrentSession();
session.beginTransaction();
//List<Topic> topics=(List<Topic>)session.createCriteria(Topic.class).list();
List<Topic> topics=(List<Topic>)session.createQuery("from Topic t left join fetch t.category c").list();
for (Topic t:topics) {
System.out.println(t.getId()+"----"+t.getTitle());
System.out.println(t.getCategory().getName());
}
session.getTransaction().commit();
}
========================================================================
nativeSQL(本地sql,功能强大)>HQL>EJBQL(是hql的子集)>QBC(query by cretra,cretra接口查询)>QBE
============================================================
===============================hibernate n+1 over=========================