泛化关系
通过对象之间的继承来实现
关联关系
通过一个对象持有另一个对象的实例来实现
类与类之间最常见的关系就是关联关系
create table t_dept(
id int primary key auto_increment,
name varchar(200)
)engine=Innodb default charset=utf8;
create table t_emp(
id int primary key auto_increment,
name varchar(200),
dept_id int,
foreign key(dept_id) references t_dept(id)
)engine=Innodb default charset=utf8;
多对一关系:多个员工在同一个部门
? 多方 ——> 员工
? 一方 ——> 部门
public class Emp implements Serializable {
private Integer id;
private String name;
private Dept dept; // 在多方定义一方的引用
//...
}
<!--
配置多对一关系
name:属性名
column:列名,外键列
class:属性的类型
-->
<many-to-one name="dept" column="dept_id" class="Dept"></many-to-one>
调用load/get查询对象时,默认只会查询当前类对象的表,不会查询关联表数据,称为关联数据的延迟加载
只有当第一次访问时才会进行数据的查询
Session session = HibernateUtil.getSession();
TransactionManager.beginTransaction();
Emp emp=(Emp) session.get(Emp.class, 1);
System.out.println(emp.getName());
System.out.println("--------------------------");
System.out.println(emp.getDept().getName());
TransactionManager.commit();
? 当执行下面代码时会出现no Session问题
Emp emp=null;
try {
Session session = HibernateUtil.getSession();
TransactionManager.beginTransaction();
emp=(Emp) session.get(Emp.class, 1);
System.out.println(emp.getName());
System.out.println("--------------------------");
TransactionManager.commit();
} catch (Exception e) {
TransactionManager.rollback();
e.printStackTrace();
} finally {
HibernateUtil.close();
}
System.out.println(emp.getDept().getName());
? 如何解决:
<!--
lazy:数据加载策略,可取值如下
false:立即加载关联数据
使用的是:两次查询
proxy:懒加载,以代理对象的方式进行延迟加载,默认值
no-proxy:懒加载, 该方式在编译时需要进行 字节码增强,否则和proxy没区别,很少使用
-->
<many-to-one name="dept" column="dept_id" class="Dept" lazy="no-proxy"></many-to-one>
<!--
fetch:抓取数据,可取值如下
join:立即加载,使用联接查询
使用的是:一次查询!!
注:此时会lazy配置无效,总是会立即加载关联数据,使用联接查询
select: 懒加载,会再执行一次selecg查询,默认值
-->
<many-to-one name="dept" column="dept_id" class="Dept" lazy="false" fetch="join"></many-to-one>
Emp emp= null;
try {
Session session = HibernateUtil.getSession();
TransactionManager.beginTransaction();
String hql="from Emp e where e.id=:id";
emp=(Emp) session.createQuery(hql).setInteger("id", 1).uniqueResult();
System.out.println(emp.getName());
System.out.println("----------------------");
TransactionManager.commit();
} catch (Exception e) {
TransactionManager.rollback();
e.printStackTrace();
} finally {
HibernateUtil.close();
}
System.out.println(emp.getDept().getName());
结论:对于HQL查询,lazy配置项有效,fetch配置项无效
? left join 只做联接操作,不查关联数据
? 根据lazy配置项,择机进行再次查询
? left join fetch既做联接操作,也查关联数据
? lazy配置项无效,总是使用联接查询,一次性将数据都查询出来
? 添加操作:
多方对象中的一方为null 或持久态 或 游离态
? 正常保存
?
多方对象中的一方为临时态
? 报错:
org.hibernate.TransientObjectException: object references an unsaved transient instanc
解决方法:
<!--
cascade:级联操作
none:不进行级联操作,默认值
all:对所有操作进行级联操作(insert/delete/update)
save-update:执行保存和更新时进行级联操作
delete:执行删除时进行级联操作,主要用于一对多操作
-->
<many-to-one name="dept" column="dept_id" class="Dept" lazy="false" fetch="select" cascade="delete"></many-to-one>
create table t_class(
id int primary key auto_increment,
name varchar(200)
)engine=Innodb default charset=utf8;
create table t_student(
id int primary key auto_increment,
name varchar(200),
class_id int,
foreign key(class_id) references t_class(id)
)engine=Innodb default charset=utf8;
一对多关联:一个班级包含多名学生
? 一方 —— > 班级
? 多方 —— > 学生
<!--
配置一对多关系
name:属性名
table:属性关联的表
cascade:级联操作
none
all
save-update
delete:级联删除,删除的过程:
1.将所有引用一方数据的外键全部设置为null
将clazz对象对应的所有student的class_id都设置为null
2.删除对应set集合中的数据
将clazz中的set集合中的student删除
3.删除自己对应的数据
将clazz对象删除
-->
<set name="students" table="t_student" lazy="false" fetch="join" cascade="delete">
<!-- 关联的列,外键列,即关联表t_student中的哪个字段关联到t_class表 -->
<key column="class_id"></key>
<!-- 关联的类,属性的类型 -->
<one-to-many class="Student"/>
</set>
? inverse 反转,一般指控制权的反转
<!--
inverse:反转
false:一方维护关联关系,默认值
true:由对方维护关联关系,即由多方维护,一方放弃对set集合的维护
-->
<set name="students" table="t_student" lazy="true" fetch="select" inverse="true">
? 前面我们配置的都是单向的关系:
单向一对多
?如果同时配置了单向多对一和单向一对多,则就是双向一对多 或 双向多对一
?inverse属性只能在<set>中配置,一般都会配置,因为关联关系由多方维护更合适
? 重写实体类的toString()的方法
Exception in thread "main" java.lang.StackOverflowError
原因:因为重写了关联实体的toString()方法,并且包含关联属性,当调用toString()方法时会导航查询关联对象,关联对象双会导航查询对方,最终导致栈溢出。
解决:不要重写toString()方法,或者 重写toString()时不要包含关联属性
关系型数据库中如何实现多对多关系?
create table t_stu(
id int primary key auto_increment,
name varchar(200)
)engine=Innodb default charset=utf8;
create table t_course(
id int primary key auto_increment,
name varchar(200)
)engine=Innodb default charset=utf8;
create table t_stu_course(
id int primary key auto_increment,
stu_id int,
course_id int,
foreign key(stu_id) references t_stu(id),
foreign key(course_id) references t_course(id)
)engine=Innodb default charset=utf8;
多对多关系:一个学生可以选择多门课程,一个课程也可以被多个学生选择
<!-- 配置多对多关系 -->
<set name="courses" table="t_stu_course">
<!-- 关联到当前类Stu的外键列 -->
<key column="stu_id"></key>
<!-- class指定属性的类型,column指定关系的列,外键列 -->
<many-to-many class="Course" column="course_id"></many-to-many>
</set>
create table t_card(
id int primary key auto_increment,
name varchar(200)
)engine=Innodb default charset=utf8;
create table t_person(
id int primary key auto_increment,
name varchar(200),
card_id int unique, -- 通过指定unique将多对一关系变成一对一关系
foreign key(card_id) references t_card(id)
)engine=Innodb default charset=utf8;
<!--
使用many-to-one配置一对一关联关系,通过unique变为一对关联关系
name:属性名
column:外键列
class:属性类型
unique:将多对一变成一对一
-->
<many-to-one name="card" column="card_id" class="Card" unique="true"></many-to-one>
<!--
使用one-to-one配置一对一关联关系
property-ref:引用的关联类的属性,使用外键关联
-->
<one-to-one name="person" class="Person" property-ref="card"></one-to-one>
? 通过主键来指定一对一的关系
? 将一个对象的多个属性封装成单独的另一个对象,这个封装的对象称为组件Component,组件不需要单独的映射文件
? 对象关系:一个对象是另一个对象的一部分
create table t_consumer(
id int primary key auto_increment,
age int,
first_name varchar(200),
last_name varchar(200)
)engine=Innodb default charset=utf8;
<!--
配置组件映射关系
name:属性名
class:属性类型
-->
<component name="name" class="Name">
<property name="firstName" column="first_name"></property>
<property name="lastName" column="last_name"></property>
</component>
原文:http://blog.51cto.com/12402007/2159436