关于Hibernate框架
一. 主键生成方式
1. 在映射关系文件中,需要配置主键字段,并配置其主键的生成
方式, 即通过generator标记来配置主键生成的方式。
2. 主键生成的方式有如下:
(1) sequence(*)
---语法
<generator class="sequence">
<param name="sequence">
序列名
</param>
</generator>
---解释
sequence是采用序列方式生成主键,适用于Oracle数据库。
(2) identity(*)
---语法
<generator class="identity">
</generator>
---解释
identity是使用数据库自增长的机制来生成主键,适用于
除了Oracle以外的数据库。
(3) native(*)
---语法
<generator class="native">
<param name="sequence">
序列名
</param>
</generator>
---解释
native是让Hibernate自动选择一个主键生成方式,它
会根据主配置文件中指定的方言,从sequence和identity中
选择一个。即如果配置的方言是Oracle则选择sequence,否则
就选择identity。
(4)increment
---语法
<generator class="increment">
</generator>
---解释
increment是采用Hibernate组件生成的ID,并不是使用
数据库的机制。该组件会自动取出当前表的ID最大值,然后+1
作为新的ID。
优点:适用于所有数据库。
缺点:当并发量大时,会出现重复主键的情况。
不推荐使用。
(5)assigned
---语法
<generator class="assigned">
</generator>
---解释
assigned,Hibernate不会自动生成主键,主键的生成完全交给
程序员来处理。
(6)hilo/uuid
---语法
<generator class="hilo或uuid">
</generator>
---解释
采用hilo/uuid的算法来生成一个主键,该主键
是一个很长的字符串,并且没有规律,但是可以保证
不重复。
二. 一级缓存
1.什么是一级缓存
Hibernate在创建session时,会给每一个session分配一块
内存空间,用于缓存查询到的对象数据,这块内存空间称之为
一级缓存。由于该空间是给session使用的,也称session级缓存。
重点:
(1)一级缓存又称为session级缓存
(2)一级缓存是session独享的
2.为什么用一级缓存
(1) 作用
一级缓存可以降低数据库访问次数,提高代码执行效率。
(2) 步骤
---session取值时会优先向它的一级缓存取值
---如果缓存中没有数据,它会向数据库取值,并将
取到的值放入一级缓存,然后session从缓存中取出数据。
---当再次查询相同的数据时,由于一级缓存中已经存在了该
数据,则直接返回,不需要重新访问数据库。
3.如何使用一级缓存
(1)一级缓存是默认开启的,自动使用
(2)规则:
---一级缓存是session独享的,即一个session不能
访问另一个session缓存的数据
---每次查询,session仅仅是把本次查询结果放到一级
缓存中
---如果查询到的结果是多条数据,session这些数据拆开,
以单个对象的形式存入一级缓存。
---在执行save,update,delete时,会自动触发缓存的
更新(与对象持久性有关)。
(3)一级缓存是给session使用的,并且是由session负责管理,
session管理一级缓存的方式如下:
a. session.evict(obj)
evict可以将obj对象从当前session的缓存区移除.
b. session.clear()
clear可以将当前session的缓存区清空
c. session.close()
session关闭时,它会释放自己的缓存区域,从而
缓存数据也释放了。
三. 对象持久性
1. Hibernate下,可以把对象看做具有3种状态,分别为临时态,持久
态,游离态,对象持久性是指对象在这三种状态之间的转换规则。
2. 三种状态的转换及规则
(1)临时态
a. 转换
--new出来的对象是临时态的
--delete持久态的对象,它将转变为临时态
b. 规则
--临时态的对象可以被垃圾回收
--临时态的对象没有被持久化过,并且没有与session建立关联。
(2)持久态
a.转换
--通过save/update操作过的对象是持久态的。
--经过get/load/list/iterate方法查询到的对象是持久态的。
b.规则
--持久态的对象不能被垃圾回收
--持久态的对象被持久化了,并且与session建立起了关联。
--(*)持久态的对象存在于一级缓存中
--(*)持久态的对象可以自动与数据库同步,同步的时机
是调用session.flush()时,实际上事务提交时也可以
同步,原因是 ts.commit()=session.flush()+commit;
(3)游离态
a. 转换
--通过evict/clear/close操作过的对象,是游离态的
b. 规则
--游离态的对象可以被垃圾回收
--游离态的对象被持久化过,但是已经与session解除了关联。
一. 关联映射
1.什么是关联映射
如果两张表有关联关系,Hibernate允许我们将此关系提取
出来,并配置在映射关系文件中。在对其中一张表进行增、删、
改、查时,Hibernate可以通过这个关系的描述,自动生成对另
一张表的增、删、改、查的SQL,并自动执行。这种对两张表的
关系的配置及使用,称之为关联映射。
2.关联映射的作用
当我们操作一张表时,可以通过关联映射自动生成操作另一张表的
SQL,并自动执行。
3.使用步骤
(1)明确两张表的关系,以及关联字段。
(2)在实体类中追加关联属性,来封装关联查询的结果。
(3)在映射关系文件中,追加2张表的关联关系配置。
4.关联映射的类型
(1)一对多
(2)多对一
(3)多对多
二. 一对多关联
1.作用
可以在我们访问"一"的一方数据时,自动访问"多"的一方
的数据,比如:在查询账务账号时,自动查询出它对应的全部
业务账号。
2.案例
在查询账务账号时,连带查询出它对应的所有业务账号。
3.开发步骤
(1)明确表的关系及关联字段
account表与service表具有一对多的关系,其关联字段
是service.account_id=account.account_id
(2)在实体类中追加关联属性
在Account中追加属性来封装业务账号数据,即增加集合类型
属性,集合中封装的是Service,如 Set<Service> services;
(3)在映射关系文件中配置关联关系
需要动态拼写如下SQL:
select * from service where account_id=?
需要哪些条件:
a、表名
b、关联字段
c、2张表的关系
d、查询结果存在哪个属性上
有一个默认前提:
一的一方表的主键,作为多的一方表的外键。即account
表的主键,作为service表的外键。
语法:
<!--指定条件d-->
<set name="services">
<!--指定条件b-->
<key column="account_id"/>
<!--指定条件a、c-->
<one-to-many class="entity.Service"/>
</set>
三.多对一关联
1.作用
设置好多对一关联之后,可以在操作"多"的一方数据时,自动操作
另一方的数据,比如在操作service时自动操作account
2.案例
希望在查询业务账号时,自动查询出该业务账号对应的账务账号。
3.开发步骤
(1)明确关联关系及关系字段。
service与account具有多对一的关系,关系字段是service.account_id=account.id
(2)在实体类中追加关联属性
在Service中追加属性Account account;
(3)在映射关系文件中增加配置
需要拼如下的SQL
select * from account where account_id in(
select account_id from service where service_id=?
);
需要提供如下条件:
a 对方表名
b 关系字段
c 表之间的关系
d 查询结果封装到哪个属性
语法:
<!--
many-to-one:c
name,class:d
column:b
class:a
-->
<many-to-one
name="account"
column="account_id"
class="entity.Account"
/>
(4) 注意
多对一关联时,Service类中的accountId 可以省略,并且
Service.hbm.xml中的accountId 的配置也可以省略。
原因是这个外键属性主要是用于查询Account数据的,但是现在
多对一关联已经把Account查询出来了,因此该查询就可以省略。
四. 关联操作
1.关联查询
(1)延迟加载
对于关联属性,Hibernate默认采用延迟加载的机制。
lazy="true": 采用延迟加载(默认)
lazy="false":不采用延迟加载
(2)采用连接查询
fetch="select":不采用连接查询(默认)
fetch="join" :采用连接查询,此时lazy属性失效。
(3)采用join fetch拼hql
--account关联service
from Account a join fetch a.services where a.id=?
(提示:由于是hql语句,所以where后面a.id中的id是属性名,不能使account_id字段名)
--service关联account
from Service s join fetch s.account where s.id=?
(提示:意义同上)
2.级联操作
(1) 什么叫级联操作
在Hibernate里,在对一方进行增、删、改时要自动的对另一方
也进行增、删、改,这样的行为称之为级联操作。
(2) 如何实现级联的添加,修改,删除
在要操作的对象的映射关系文件中,在关联属性上追加cascade属性,
用这个属性的值来指定级联方式:
cascade="none"
不支持级联(默认)
cascade="save-update"
支持级联添加、修改
cascade="delete"
支持级联删除
cascade="all"
支持级联添加、修改、删除
(3)案例
在添加、修改、删除账务账号时,同时添加、修改、删除业务账号。
注:通常情况下,都是通过"一"的一方来级联"多"的一方,很少
有通过"多"级联"一"的情况。
(4)inverse
在一对多进行级联添加、删除时,Hibernate在操作主表account时,
它认为外键字段有必要由account方来进行维护,因此它会
以acccount方触发一个单独更新外键字段的行为,即
update service set account_id=?/null where service_id=?
而实际上,级联添加、删除service时,添加、删除本身就已经可以
维护外键字段(由于外键在service表中),因此一对多时主表触发
的外键维护时多余的,可以去掉,所以把inverse="false"这种默认
值该为inverse="true"就可以达到让主表放弃维护外键的目的了。
注: inverse="true"中inverse是反转的意思,整句是指主表方反转对
外键字段的维护权,即交出这个维护权,所以此时主表不再生成
update语句维护外键字段。
(5)注意:
级联删除时,需要在配置文件的关联属性上追加inverse="true"
五.多对多关系映射
1.作用
在操作一方对象时,Hibernate可以自动根据关系映射操作另一方,
操作包含增、删、改、查。
2.案例
在查询管理员时,可以自动查询对应的角色,在新增、修改、删除
管理员时,可以自动新增、修改、删除管理员角色中间表。
3.开发步骤
(1)明确关联关系及关系字段
admin_info与role_info具有多对多的关系,关系字段是:
admin_role.admin_id=adminer_info.id
admin_role.role_id=role_info.id
(2)实体类中追加关联属性
在管理员实体类Admin中追加属性封装角色,即Set<Role> roles;
(3)在映射关系文件中配置关系
需要自动拼如下sql:(可查询出某个管理员对应的角色)
select * from role_info where role_id in(
select role_id from admin_role where admin_id=?
);
需要提供如下条件:
a. 对方表名role_info
b. 中间表名admin_role
c. 对方表的关联字段role_id
d. 当前表的关联字段admin_id
e. 2张表的关系
d. 查询结果封装到哪个属性
配置语法:
<!--b,f-->
<set name="roles" table="admin_role">
<!--d-->
<key column="admin_id"/>
<!--a,c,e-->
<many-to-many
class="entity.Role"
column="role_id" />
</set>
4.关联操作
(1)关联查询
a. lazy属性的使用同一对多
b. fetch属性的使用同一对多
c. join fetch(即拼写hql来进行多对多的关联)
(2)关联增加、修改、删除
在增加、修改、删除当前表时,自动增加、修改、删除中间表的数据
(3)级联增加、修改、删除
在增加、修改、删除当前表时,自动增加、修改、删除对方表以及
中间表的数据。
cascade="save-update"
增加,修改
cascade="delete"
删除
cascade="all"
增加,修改,删除
一. 主键生成方式
1. 在映射关系文件中,需要配置主键字段,并配置其主键的生成
方式, 即通过generator标记来配置主键生成的方式。
2. 主键生成的方式有如下:
(1) sequence(*)
---语法
<generator class="sequence">
<param name="sequence">
序列名
</param>
</generator>
---解释
sequence是采用序列方式生成主键,适用于Oracle数据库。
(2) identity(*)
---语法
<generator class="identity">
</generator>
---解释
identity是使用数据库自增长的机制来生成主键,适用于
除了Oracle以外的数据库。
(3) native(*)
---语法
<generator class="native">
<param name="sequence">
序列名
</param>
</generator>
---解释
native是让Hibernate自动选择一个主键生成方式,它
会根据主配置文件中指定的方言,从sequence和identity中
选择一个。即如果配置的方言是Oracle则选择sequence,否则
就选择identity。
(4)increment
---语法
<generator class="increment">
</generator>
---解释
increment是采用Hibernate组件生成的ID,并不是使用
数据库的机制。该组件会自动取出当前表的ID最大值,然后+1
作为新的ID。
优点:适用于所有数据库。
缺点:当并发量大时,会出现重复主键的情况。
不推荐使用。
(5)assigned
---语法
<generator class="assigned">
</generator>
---解释
assigned,Hibernate不会自动生成主键,主键的生成完全交给
程序员来处理。
(6)hilo/uuid
---语法
<generator class="hilo或uuid">
</generator>
---解释
采用hilo/uuid的算法来生成一个主键,该主键
是一个很长的字符串,并且没有规律,但是可以保证
不重复。
二. 一级缓存
1.什么是一级缓存
Hibernate在创建session时,会给每一个session分配一块
内存空间,用于缓存查询到的对象数据,这块内存空间称之为
一级缓存。由于该空间是给session使用的,也称session级缓存。
重点:
(1)一级缓存又称为session级缓存
(2)一级缓存是session独享的
2.为什么用一级缓存
(1) 作用
一级缓存可以降低数据库访问次数,提高代码执行效率。
(2) 步骤
---session取值时会优先向它的一级缓存取值
---如果缓存中没有数据,它会向数据库取值,并将
取到的值放入一级缓存,然后session从缓存中取出数据。
---当再次查询相同的数据时,由于一级缓存中已经存在了该
数据,则直接返回,不需要重新访问数据库。
3.如何使用一级缓存
(1)一级缓存是默认开启的,自动使用
(2)规则:
---一级缓存是session独享的,即一个session不能
访问另一个session缓存的数据
---每次查询,session仅仅是把本次查询结果放到一级
缓存中
---如果查询到的结果是多条数据,session这些数据拆开,
以单个对象的形式存入一级缓存。
---在执行save,update,delete时,会自动触发缓存的
更新(与对象持久性有关)。
(3)一级缓存是给session使用的,并且是由session负责管理,
session管理一级缓存的方式如下:
a. session.evict(obj)
evict可以将obj对象从当前session的缓存区移除.
b. session.clear()
clear可以将当前session的缓存区清空
c. session.close()
session关闭时,它会释放自己的缓存区域,从而
缓存数据也释放了。
三. 对象持久性
1. Hibernate下,可以把对象看做具有3种状态,分别为临时态,持久
态,游离态,对象持久性是指对象在这三种状态之间的转换规则。
2. 三种状态的转换及规则
(1)临时态
a. 转换
--new出来的对象是临时态的
--delete持久态的对象,它将转变为临时态
b. 规则
--临时态的对象可以被垃圾回收
--临时态的对象没有被持久化过,并且没有与session建立关联。
(2)持久态
a.转换
--通过save/update操作过的对象是持久态的。
--经过get/load/list/iterate方法查询到的对象是持久态的。
b.规则
--持久态的对象不能被垃圾回收
--持久态的对象被持久化了,并且与session建立起了关联。
--(*)持久态的对象存在于一级缓存中
--(*)持久态的对象可以自动与数据库同步,同步的时机
是调用session.flush()时,实际上事务提交时也可以
同步,原因是 ts.commit()=session.flush()+commit;
(3)游离态
a. 转换
--通过evict/clear/close操作过的对象,是游离态的
b. 规则
--游离态的对象可以被垃圾回收
--游离态的对象被持久化过,但是已经与session解除了关联。
一. 关联映射
1.什么是关联映射
如果两张表有关联关系,Hibernate允许我们将此关系提取
出来,并配置在映射关系文件中。在对其中一张表进行增、删、
改、查时,Hibernate可以通过这个关系的描述,自动生成对另
一张表的增、删、改、查的SQL,并自动执行。这种对两张表的
关系的配置及使用,称之为关联映射。
2.关联映射的作用
当我们操作一张表时,可以通过关联映射自动生成操作另一张表的
SQL,并自动执行。
3.使用步骤
(1)明确两张表的关系,以及关联字段。
(2)在实体类中追加关联属性,来封装关联查询的结果。
(3)在映射关系文件中,追加2张表的关联关系配置。
4.关联映射的类型
(1)一对多
(2)多对一
(3)多对多
二. 一对多关联
1.作用
可以在我们访问"一"的一方数据时,自动访问"多"的一方
的数据,比如:在查询账务账号时,自动查询出它对应的全部
业务账号。
2.案例
在查询账务账号时,连带查询出它对应的所有业务账号。
3.开发步骤
(1)明确表的关系及关联字段
account表与service表具有一对多的关系,其关联字段
是service.account_id=account.account_id
(2)在实体类中追加关联属性
在Account中追加属性来封装业务账号数据,即增加集合类型
属性,集合中封装的是Service,如 Set<Service> services;
(3)在映射关系文件中配置关联关系
需要动态拼写如下SQL:
select * from service where account_id=?
需要哪些条件:
a、表名
b、关联字段
c、2张表的关系
d、查询结果存在哪个属性上
有一个默认前提:
一的一方表的主键,作为多的一方表的外键。即account
表的主键,作为service表的外键。
语法:
<!--指定条件d-->
<set name="services">
<!--指定条件b-->
<key column="account_id"/>
<!--指定条件a、c-->
<one-to-many class="entity.Service"/>
</set>
三.多对一关联
1.作用
设置好多对一关联之后,可以在操作"多"的一方数据时,自动操作
另一方的数据,比如在操作service时自动操作account
2.案例
希望在查询业务账号时,自动查询出该业务账号对应的账务账号。
3.开发步骤
(1)明确关联关系及关系字段。
service与account具有多对一的关系,关系字段是service.account_id=account.id
(2)在实体类中追加关联属性
在Service中追加属性Account account;
(3)在映射关系文件中增加配置
需要拼如下的SQL
select * from account where account_id in(
select account_id from service where service_id=?
);
需要提供如下条件:
a 对方表名
b 关系字段
c 表之间的关系
d 查询结果封装到哪个属性
语法:
<!--
many-to-one:c
name,class:d
column:b
class:a
-->
<many-to-one
name="account"
column="account_id"
class="entity.Account"
/>
(4) 注意
多对一关联时,Service类中的accountId 可以省略,并且
Service.hbm.xml中的accountId 的配置也可以省略。
原因是这个外键属性主要是用于查询Account数据的,但是现在
多对一关联已经把Account查询出来了,因此该查询就可以省略。
四. 关联操作
1.关联查询
(1)延迟加载
对于关联属性,Hibernate默认采用延迟加载的机制。
lazy="true": 采用延迟加载(默认)
lazy="false":不采用延迟加载
(2)采用连接查询
fetch="select":不采用连接查询(默认)
fetch="join" :采用连接查询,此时lazy属性失效。
(3)采用join fetch拼hql
--account关联service
from Account a join fetch a.services where a.id=?
(提示:由于是hql语句,所以where后面a.id中的id是属性名,不能使account_id字段名)
--service关联account
from Service s join fetch s.account where s.id=?
(提示:意义同上)
2.级联操作
(1) 什么叫级联操作
在Hibernate里,在对一方进行增、删、改时要自动的对另一方
也进行增、删、改,这样的行为称之为级联操作。
(2) 如何实现级联的添加,修改,删除
在要操作的对象的映射关系文件中,在关联属性上追加cascade属性,
用这个属性的值来指定级联方式:
cascade="none"
不支持级联(默认)
cascade="save-update"
支持级联添加、修改
cascade="delete"
支持级联删除
cascade="all"
支持级联添加、修改、删除
(3)案例
在添加、修改、删除账务账号时,同时添加、修改、删除业务账号。
注:通常情况下,都是通过"一"的一方来级联"多"的一方,很少
有通过"多"级联"一"的情况。
(4)inverse
在一对多进行级联添加、删除时,Hibernate在操作主表account时,
它认为外键字段有必要由account方来进行维护,因此它会
以acccount方触发一个单独更新外键字段的行为,即
update service set account_id=?/null where service_id=?
而实际上,级联添加、删除service时,添加、删除本身就已经可以
维护外键字段(由于外键在service表中),因此一对多时主表触发
的外键维护时多余的,可以去掉,所以把inverse="false"这种默认
值该为inverse="true"就可以达到让主表放弃维护外键的目的了。
注: inverse="true"中inverse是反转的意思,整句是指主表方反转对
外键字段的维护权,即交出这个维护权,所以此时主表不再生成
update语句维护外键字段。
(5)注意:
级联删除时,需要在配置文件的关联属性上追加inverse="true"
五.多对多关系映射
1.作用
在操作一方对象时,Hibernate可以自动根据关系映射操作另一方,
操作包含增、删、改、查。
2.案例
在查询管理员时,可以自动查询对应的角色,在新增、修改、删除
管理员时,可以自动新增、修改、删除管理员角色中间表。
3.开发步骤
(1)明确关联关系及关系字段
admin_info与role_info具有多对多的关系,关系字段是:
admin_role.admin_id=adminer_info.id
admin_role.role_id=role_info.id
(2)实体类中追加关联属性
在管理员实体类Admin中追加属性封装角色,即Set<Role> roles;
(3)在映射关系文件中配置关系
需要自动拼如下sql:(可查询出某个管理员对应的角色)
select * from role_info where role_id in(
select role_id from admin_role where admin_id=?
);
需要提供如下条件:
a. 对方表名role_info
b. 中间表名admin_role
c. 对方表的关联字段role_id
d. 当前表的关联字段admin_id
e. 2张表的关系
d. 查询结果封装到哪个属性
配置语法:
<!--b,f-->
<set name="roles" table="admin_role">
<!--d-->
<key column="admin_id"/>
<!--a,c,e-->
<many-to-many
class="entity.Role"
column="role_id" />
</set>
4.关联操作
(1)关联查询
a. lazy属性的使用同一对多
b. fetch属性的使用同一对多
c. join fetch(即拼写hql来进行多对多的关联)
(2)关联增加、修改、删除
在增加、修改、删除当前表时,自动增加、修改、删除中间表的数据
(3)级联增加、修改、删除
在增加、修改、删除当前表时,自动增加、修改、删除对方表以及
中间表的数据。
cascade="save-update"
增加,修改
cascade="delete"
删除
cascade="all"
增加,修改,删除