嗯,又要开始......了
一、前言
1.1 EE 的三层架构
1.2 什么是ORM
ORM:Object Relational Mapping(对象关系映射)。指的是将一个Java中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表。
二、入门
2.1 版本及目录
Hibernate3.X很多企业使用
Hibernate4.X不需要掌握,过渡版本(结构改变很多)
Hibernate5.X最新版本,配置同3
documentation :Hibernate开发的文档
lib :Hibernate开发包
>required :Hibernate开发的必须的依赖包
>optional :Hibernate开发的可选的jar包
project :Hibernate提供的项目
2.2 基本配置
-
映射需要通过XML的配置文件来完成,这个配置文件可以任意命名。尽量统一命名规范(类名.hbm.xml)
-
Hibernate的核心配置文件的名称:hibernate.cfg.xml
2.3 映射配置
【class标签的配置】
标签用来建立类与表的映射关系
属性:
name :类的全路径
table :表名(类名与表名一致,table可以省略)
catalog :数据库名
【id标签的配置】
标签用来建立类中的属性与表中的主键的对应关系
属性:
name :类中的属性名
column :表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
length :长度
type :类型
【property标签的配置】
标签用来建立类中的普通属性与表的字段的对应关系
属性:
name :类中的属性名
column :表中的字段名
length :长度
type :类型
not-null :设置非空
unique :设置唯一
2.4 核心配置
-
配置方式
- hibernate.properties
- hibernate.cfg.xml
配置
必须的配置
连接数据库的基本的参数
驱动类
url路径
用户名
密码
方言
可选的配置
显示SQL :hibernate.show_sql
格式化SQL :hibernate.format_sql
自动建表 :hibernate.hbm2ddl.auto
none :不使用hibernate的自动建表
create :如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试)
create-drop :如果数据库中已经有表,删除原有表,执行操作,删除这个表。如果没有表,新建一个,使用完了删除该表。(测试)
update :如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)
validate :如果没有表,不会创建表。只会使用数据库中原有的表。(校验映射和表结构)。
映射文件的引入
<mapping resource="com/tcy/java/Customer.hbm.xml"/>
2.5 Hibernate的配置对象
SessionFactory线程安全
Session非线程安全、不能定义为全局,只可局部
-
Session API
Session代表的是Hibernate与数据库的链接对象。不是线程安全的。与数据库交互桥梁。
1. 保存方法:
Serializable save(Object obj);
2. 查询方法:
T get(Class c,Serializable id);
T load(Class c,Serializable id);
get方法和load方法的区别?
- 修改方法:
void update(Object obj); - 删除方法:
void delete(Object obj); - 保存或更新:
void saveOrUpdate(Object obj) - 查询方法:
2.6 事物对象
Hibernate中管理事务的对象。
commit();
rollback();
三、主键缓存及事物
3.1 Hibernate的持久化类的编写规则
- 无参数构造
- 属性私有
- 属性尽量使用包装类
- 提供一个唯一OID与主键对应
- 不要使用final修饰(会导致load失效)
3.2 Hibernate的主键生成策略
(1)主键分类
自然主键
指业务相关,由用户指定,且能唯一标识数据库中的任意一条记录-
代理主键
指与业务无关且能唯一标识数据库中记录,一般是数据库自动生成的,比如mysql可以使用auto_increment,Sql2000可以使用identity生成方式,oracle可以使用sequence生成方式
(2)主键生成策略1、increment:hibernate中提供的自动增长机制,适用于short、int、long类型的主键。在单线程程序中使用。 首先先发送一条语句:select max(id) from 表,然后id+1作为下一条记录的主键 2、identity:适用于short、int、long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长的数据库(MySQL、MSSQL)但是Oracle无 3、sequence:适用于short、int、long类型的主键,采用的是序列的方式(Oracle支持),MySQL不支持 4、uuid:适用于字符串类型主键。使用hibernate中的随机方式生成字符串主键。 5、native:本地策略,可以在identity和sequence之间进行自动切换。 6、assigned:hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置 7、foreign:外部的。一对一的一种关联映射的情况下使用。(了解)
3.3 持久化类的三种状态
- 瞬时态:没有唯一标识OID,没有被session管理
- 持久态:有唯一标识OID,已经被session管理
- 脱管态:有唯一标识OID,没有被session管理
- 状态转换:(了解)
3.4 一级缓存
- Hibernate优化手段,称为是session级别缓存。
-
快照区
3.5 事务管理
事务:事务指的是逻辑上的一组操作,组成这组操作的各个逻辑单元要么全都成功,要么全都失败
- 事务的特性
- 原子性:代表事务不可分隔
- 一致性:代表事务执行的前后,数据的完整性保持一致
- 隔离性:代表一个事务执行的过程中,不应该受到其它事务的干扰
- 持久性:代表事务执行完成后,数据就持久化到数据库
- 如果不考虑隔离性,引发安全性问题
- 读问题
- 脏读:一个事务读到另一个事务未提交的数据。
- 不可重复读:一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致
- 虚读:一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结果不一致
- 写问题(了解)
- 引发两类丢失更新
- 读问题的解决
- 设置事务的隔离级别
- Read uncommitted:以上读问题都会发生1
- Read committed:解决脏读,但是不可重复读和虚读有可能发生(Oracle使用)2
- Repeatable read:解决脏读和不可重复度,但是虚读有可能发送(MySQL使用)4
- Serializable:解决所有读问题8
-
hibernate中设置事务的隔离级别
- Service层事务
- Hibernate解决Service的事务管理
* 必须保证链接对象是同一个
1. 向下传递 DBUtils
2. 使用ThreadLocal对象
将这个连接绑定到当前线程中
在DAO的方法中,通过当前的线程获得到连接对象
* Hibernate框架内部已经绑定好了ThreadLocal
1. 早SessionFactory中提供了一个方法getCurrentSession();
2. 通过一个配置完成。
3. <property name="hibernate.current_session_context_class">thread</property>
thread:Session 对象的生命周期与本地线程绑定
jta:Session 对象的生命周期与JTA事务绑定(跨数据库)
managed:Hibernate 委托程序来管理 Session 对象的生命周期
4. 无需session.close(); 线程结束会自动关闭session
3.6 Hibernate的其他的API
- Query
- Query 接口用于接收HQL,查询多个对象
-
HQL:hibernate查询语言,这种语言与SQL的语法及其类似,面向对象的查询语言。
-
- Criteria
- Criteria:QBC(Query By Criteria)
-
更加面向对象的一种查询方式
-
- SQLQuery
- SQLQuery用于接收SQL。特别复杂情况下使用SQL
四、关系映射
1 一对多关系(双向数据绑定)
- 多的一方映射
<!-- 配置多对一的关系:放置的是一的一方的对象 -->
<!--
many-to-one标签
* name :一的一方的对象的属性名称。
* class :一的一方的类的全路径。
* column :在多的一方的表的外键的名称。
-->
<many-to-one name="customer" cascade="save-update,delete"
class="com.itheima.hibernate.domain.Customer" column="lkm_cust_id" />
- 一的一方映射
<!-- 配置一对多的映射:放置的多的一方的集合 -->
<!--
set标签 :
* name :多的一方的对象集合的属性名称。
* cascade:级联
* inverse:放弃外键维护权。
-->
<set name="linkMans" cascade="save-update,delete" inverse="true">
<!--
key标签
* column:多的一方的外键的名称。
-->
<key column="lkm_cust_id" />
<!--
one-to-many标签
* class :多的一方的类的全路径
-->
<one-to-many class="com.itheima.hibernate.domain.LinkMan" />
</set>
- 一对多的级联操作
操作一个对象的时候,是否会同时操作其关联的对象
添加,删除 cascade="save-update,delete" - 一对多设置了双向关联产生多余的SQL语句
单向维护
使一方放弃外键维护权
一的一方放弃。在set上配置inverse=”true”
2 多对多关系
- 映射配置
<!--
set标签
* name :对方的集合的属性名称。
* table :多对多的关系需要使用中间表,放的是中间表的名称。
-->
<set name="roles" table="sys_user_role" cascade="save-update,delete">
<!--
key标签:
* column :当前的对象对应中间表的外键的名称。
-->
<key column="user_id"/>
<!--
many-to-many标签:
* class :对方的类的全路径
* column :对方的对象在中间表中的外键的名称。
-->
<many-to-many class="com.itheima.hibernate.domain.Role" column="role_id"/>
</set>
<!--
set标签
* name :对方的集合的属性名称。
* table :多对多的关系需要使用中间表,放的是中间表的名称。
-->
<set name="users" table="sys_user_role" inverse="true" cascade="save-update,delete">
<!--
key标签:
* column :当前的对象对应中间表的外键的名称。
-->
<key column="role_id"/>
<!--
many-to-many标签:
* class :对方的类的全路径
* column :对方的对象在中间表中的外键的名称。
-->
<many-to-many class="com.itheima.hibernate.domain.User" column="user_id"/>
</set>
注意:
// 保存操作:多对多建立了双向的关系必须有一方放弃外键维护。
// 一般是被动方放弃外键维护权。
五、查询方式及抓取策略(结)
1 OID查询
OID检索:Hibernate根据对象的OID(主键)进行检索
Customer customer = session.get(Customer.class,1l);
Customer customer = session.load(Customer.class,1l);
2 对象导航检索
对象导航检索:Hibernate根据一个已经查询到的对象,获得其关联的对象的一种查询方式。
LinkMan linkMan = session.get(LinkMan.class,1l);
Customer customer = linkMan.getCustomer();
Customer customer = session.get(Customer.class,2l);
Set<LinkMan> linkMans = customer.getLinkMans();
3 HQL检索(取对象名与属性,跟表无关)
HQL查询:Hibernate Query Language,Hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL。通过session.createQuery(),用于接收一个HQL进行查询方式。
-
3.1 HQL的简单查询
-
3.2 HQL的别名查询
-
3.3 HQL的排序查询
-
3.4 HQL的条件查询
-
3.5 HQL的投影查询(需添加构造方法)
-
3.6 HQL的分页查询
-
3.7 HQL的分组统计查询
3.8 HQL的多表查询
SQL的多表查询
1.连接查询
交叉连接:笛卡尔积
select * from A,B;
内连接 :inner join (inner 可以省略)
隐式内连接:
select * from A,B where A.id = B.aid;
显示内连接:
select * from A inner join B on A.id = B.aid;
外连接 :
左外连接:left outer join(outer 可以省略)
select * from A left outer join B on A.id= B.aid;
右外连接:right outer join(outer 可以省略)
select * from A right outer join B on A.id = B.aid;
2.子查询
HQL的多表查询
连接查询
交叉连接
内连接
显示内连接
隐式内连接
迫切内连接
外连接
左外连接
右外连接
迫切左外连接
4 QBC检索
QBC查询:Query By Criteria,条件查询。是一种更加面向对象化的查询的方式。
-
4.1 简单查询
-
4.2 排序查询
-
4.3 分页查询
-
4.4 条件查询
-
4.5 统计查询
-
4.6 离线条件查询(SSH) -- DetachedCriteria
5 SQL检索
SQL查询:通过使用sql语句进行查询
6 延迟加载
延迟加载:lazy(懒加载)。执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。
- 6.1 延迟加载的分类
类级别的延迟加载
指的是通过load方法查询某个对象的时候,是否采用延迟。session.load(Customer.class,1l);
类级别延迟加载通过<class>上的lazy进行配置,如果让lazy失效
将lazy设置为false
将持久化类使用final修饰
Hibernate. Initialize()
关联级别的延迟加载
指的是在查询到某个对象的时候,查询其关联的对象的时候,是否采用延迟加载。
Customer customer = session.get(Customer.class,1l);
customer.getLinkMans();----通过客户获得联系人的时候,联系人对象是否采用了延迟加载,称为是关联级别的延迟。
抓取策略往往会和关联级别的延迟加载一起使用,优化语句。
7 抓取策略
通过一个对象抓取到关联对象需要发送SQL语句,SQL语句如何发送,发送成什么样格式通过策略进行配置。
通过<set>或者<many-to-one>上通过fetch属性进行设置
fetch和这些标签上的lazy如何设置优化发送的SQL语句
- 7.1 <set>上的fetch和lazy
fetch:抓取策略,控制SQL语句格式
select :默认值,发送普通的select语句,查询关联对象
join :发送一条迫切左外连接查询关联对象
subselect :发送一条子查询查询其关联对象
lazy:延迟加载,控制查询关联对象的时候是否采用延迟
true :默认值,查询关联对象的时候,采用延迟加载
false :查询关联对象的时候,不采用延迟加载
extra :及其懒惰。
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。
- 7.2 <many-to-one>上的fetch和lazy
fetch :抓取策略,控制SQL语句格式。
select :默认值,发送普通的select语句,查询关联对象。
join :发送一条迫切左外连接。
lazy :延迟加载,控制查询关联对象的时候是否采用延迟。
proxy :默认值,proxy具体的取值,取决于另一端的<class>上的lazy的值。
false :查询关联对象,不采用延迟。
no-proxy :(不会使用)
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。
8 批量抓取
一批关联对象一起抓取,batch-size