hibernate

Hibernate简介
什么是Hibernate
.Hibernate是数据访问层的框架,对JDBC进行了封装,是针对数据库访问提出的面向对象的解决方案.


Hibernate的作用
使用Hibernate可以直接访问对象,Hibernate自动将此访问转换成sql执行,从而达到间接访问数据库的目的,
简化了数据访问层的代码开发.

Hibernate和jdbc的对比.

Hibernate和mybatis的对比

Hibernate框架设计原理:
设计原理:
Hibernate采用了ORM思想对JDBC进行了封装.
.Hibernate框架是ORM思想的一种实现,解决了对象和数据库数据映射的问题.
.Hibernate提供了一系列的API,允许我们直接访问实体对象,然后其根据ORM映射关系,转化成SQL并执行,
从而到达访问数据库的目的.

ORM:(Object Relation Mapping),即对象关系映射.
指的是java对象和关系数据库之间的映射

.ORM思想:就是将对象与数据库进行相互转换的思想,不同的框架/技术实现ORM手段不同,
但更多是采用配置+反射的方式来实现ORM.


Hibernate框架体系结构
主配置文件
Hibernate的主配置文件是一个XML,通常命名为hibernate.cfg.xml
该文件可以配置数据库连接参数,hibernate框架参数,以及映射关系文件

映射关系文件
.映射关系文件指定了实体类和数据表的对应关系,以及类中属性和表中字段之间的对应关系.
.hibernate中使用xml文件来描述映射关系,文件通常名为"实体类.hbm.xml"
并放于实体类相同的路径下.

--练习:Hibernate的基本使用
使用hibernate完成对员工表的增删改查

方案:
hibernate的使用步骤
1.导入hibernate包,以及数据库驱动包
2.引入hibernate主配置文件hibernate.cfg.xml
3.创建实体类
4.创建映射关系文件
5.使用hibernate常用API执行增删改查操作.

.开发步骤:
准备工作:
步骤一:创建员工表emp_h
步骤二:导包
步骤三:引入hibernate主配置文件,放在src根路径下.
并在主配置文件配置好数据库连接信息,以及hibernate框架参数.
步骤四:创建实体类,用于封装员工表的信息
步骤五:创建映射关系文件
步骤六:声明映射关系文件
步骤七:创建Session工具类


hibernate主键生成策略.
4.1常用方式
sequence
.sequence是常用序列方式生成主键,适用于oracle数据库
<generator class="sequence">
<!-- 指定用于生成主键的sequence -->
<param name="sequence">emp_h_seq</param>
</generator>

identity
.identity是采用数据库自增长机制生成主键,适用于oracle之外的其他数据库

native
.native是根据当前配置的数据库方言,自动选择sequence或者identity
<generator class="native">
<!-- 指定用于生成主键的sequence -->
<param name="sequence">emp_h_seq</param>
</generator>

increment
.increment不是采用数据库自身机制来生成主键,而是使用hibernate提供的一种生成主键的方式.
他是获取当前表中主键的最大值,然后加1作为新的主键
<generator class="increment">
</generator>

ps:这种方式在并发量高时存在问题,可能会生成重复的主键,因此不推荐使用.

.assigned
assigned是hibernate不负责生成主键,需要程序员自己处理主键的生成

uuid/hilo
uuid/hilo是采用uuid/hilo算法生成一个主键值,这个主键是一个不规则的长数字.
<generator class="uuid/hilo"/>
.注意:这种方式可以保证主键不重复,但是没有规律,因此不能按主键排序

hibernate的映射类型
使用hibernate的预定义类型配置属性和字段的映射关系.
重构Emp_h.hbm.xml
将各个属性的type有java类型改为hibernate预定义类型,同时追加marry属性,并使用布尔类型配置该属性

一级缓存
什么是一级缓存.
.hibernate创建每个Session对象时,都会给该Session分配一块独立的缓存区,用于存放该Session查询出来的对象,
这个分配给Session的缓冲区称为一级缓存,也叫session级缓存.

为什么使用一级缓存
.Session取数据时,会优先向缓存区取数据,如果存在数据则直接返回,不存储才会去数据库查询,从而
降低了数据访问次数,提升了代码运行效率.

如何使用一级缓存
一级缓存是默认开启的,在使用hibernate的API进行查询时会自动使用.

一级缓存的特点:
一级缓存是session独享的,每个Session不能访问其他Session的缓冲区.
.Session的save,update,delete操作会触发缓存更新.

一级缓存的管理
.Session.evict(obj)
将obj对象从一级缓存中移除

.Session.clear()
清除一级缓存中所有的obj

.Session.close();
关闭session,释放缓存空间.


1.验证一级缓存
设计几个测试案例,已验证一级缓存的存在及特性.

1.1用同一个Session查询同一条数据2次,如果只查询一次数据库,则验证了一级缓存的存在.
1.2用两个不同的session,分别查询同一条数据,如果查询2次数据库说明一级缓存是session独享的.

对象持久性
Hibernate对象的三种状态
.在hibernate中,可以把实体对象看成三种状态,分别是临时态,持久态,游离态


临时态
.通过new创建的对象为临时态 ,不在session管理中,数据库无对应记录.
save(e)
update(e)
.通过delete方法操作的对象将转换为临时态

.特征
临时态可以被垃圾回收
临时态的对象未进行持久化操作.未与session关联

持久态
通过get,load,list,iterate等方法查询到的对象为持久态,处于session管理中,并且数据库中有对应记录
.通过save方法,update方法操作的对象转变为持久态
特征:
持久态对象垃圾回收器不能回收
-持久态的对象进行了持久化,与session相关联,实际上持久态对象存在session缓存中,由session负责管理
-持久态对象的数据可以自动更新到数据库中,时机是在调用session.flush()时执行,还有就是提交commit也会触发同步
可以理解为:commit=session.flush+commit.

游离态
-通过session的evict,clear,close方法操作的对象转变为游离态
-游离态的特征:
-游离态的对象可以被垃圾回收,不在session管理之中,数据库存在对应记录
-游离态的对象进行过持久化,但已经与session解除了关联


--验证持久态对象的特征
1.验证持久态对象存在于一级缓存中
解决方案:
新增一条数据,在新增后该数据对象称为持久态,然后根据ID查询

2.持久态对象可以自动更新至数据库
新增一条数据,在新增以后该对象为持久态对象,然后修改这个对象的任意属性值,并提交事务,在执行时
如果发现数据库中的数据是修改后的内容,则验证了持久态对象可以自动更新至数据库.


3.持久态对象更新数据库的时机是session.flush();
查询一条数据,该数据对象为持久态.修改对象的任意属性值,在调用session.flush()方法.
不提交事务,如果控制台输出更新SQL语句则验证了一级缓存对象更新至数据库的时机为session.flush();

思考
hibernate中批量插入数据该如何处理.
为了防止一级缓存溢出,需要做个判断
public void batchAdd(List<Emp_h> emps){
        Session session = HibernateUtil.getSession();    
        Transaction ts =session.beginTransaction();
        try{
            for(Emp_h e:emps){
                session.save(e);
            }
            ts.commit();
        }catch(Exception e){
            e.printStackTrace();
            //回滚事物
            ts.rollback();
        }finally{
            session.close();
        }
    }    


3.延迟加载
什么是延迟加载
.在使用某些hibernate方法查询数据时,hibernate返回的只是一个空对象(除id外属性都为null),
并没有真正的查询数据库,而在使用这个对象时才会触发查询数据库,并将查询到的数据注入到这个空对象中,
这种查询实际推迟到对象访问时的机制称之为延时加载.

为什么要用延迟加载
.提升用户体验感
.可以提升内存资源的使用率
.可以降低对数据库的访问次数

采用了延迟加载的方法
.session.load();
.关联映射中对关联属性的加载

使用延迟加载需要注意的问题
.采用具有延迟加载机制的操作,需要避免session提前关闭,避免在使用对象之前关闭session.

--练习:验证延迟加载
设计案例:验证session.load()方法在查询时使用的是延迟加载.
解决方案:
1.先查询某条emp_h的某条数据
2.输出一条分割线
3.使用查询到的对象,比如输出当前这个对象的某些属性.
4.观察控制台,如果查询用的sql语句在分割线后面,则证明该方法是使用延迟加载的.
public void testLoad(){
        Session session = HibernateUtil.getSession();    
        //load方法并没有触发访问数据库
        Emp_h emp =(Emp_h) session.load(Emp_h.class, 23);
        System.out.println("-------------------");
        //使用emp对象时才真正访问数据库
        System.out.println(emp.getName());
        session.close();
    }
}
作业:
验证query.iterate()方法也是使用了延迟加载机制的.

open  session in view
在项目中,DAO只是负责查询出数据,而使用数据的时机是在jsp解析的过程中,
因此要避免在DAO中关闭session,也就是说在视图层保持session的开启.
 
延迟加载实现原理:
采用延迟加载方法,返回的对象类型是hibernate采用
CGLIB技术在内存中动态生成的类型,该类型为原实体类的子类,并在子类中重写了属性的get方法.


关联映射
什么是关联映射
.若两张表具有关联关系,我们可以在实体对象和映射关系文件中配置这种关系,然后使用
hibernate操作其中一张表时,他可以通过配置关系自动的帮助我们操作到另一张表,
这种通过配置自动操作另一张表的字段称之为关联映射.

关联映射的作用
当我们操作一张表的时候,hibernate可以通过关联映射自动帮助我们操作另一张表
这种关联操作包括
-关联查询出关系表的数据.
-关联新增,修改关系表的数据.
-关联删除关系表的数据.

关联映射的类型
一对多关联
多对一关联
多对多关联
一对一关联
继承关联***

如何使用关联映射
1.明确两张表之间的关联关系
2.配置这种关系
3.配置的时候决定这种关系是哪种类型


1.明确两张表的关系及关系字段


2.在实体类中添加关联属性
-在实体类上体现两张表的关系,一般情况是在实体类中增加一个属性,
用于封装器关系表的数据.
3.在映射关系文件中配置关联关系.

一对多关联
什么是一对多关联
.如果两张表具有关联关系,并且关联关系类型属于一对多,那么我们在使用hibernate操作"一方数据时",
可以自动关联操作"多"方数据,那么这种关联映射称之为一对多关联.

一对多的关联作用
.可以通过"一"来操作"多",包括
-通过查询"一",自动查询"多"
-通过新增/修改"一",自动新增/修改"多".
-通过删除"一",自动删除"多"

--练习:
使用一对多关联映射,在查询账务账号时,自动查询出它对应的全部业务账号
账务账号 ------------多个业务账号

解决方案:
1.账务账号与业务账号具有一对多的关系,他们的关系子段
账务表(account)   a类+List<service>             业务表(service)
account_id  1                              service.account_id
        
2.在账务账号中追加属性,用于封装它对应的一组账号.
3.在账务账号映射关系文件中配置集合属性.

步骤一:创建账务账号实体类.Account
步骤二:创建业务账号实体类.Service
步骤三:创建账号映射关系文件
步骤四:创建业务账号映射关系文件
步骤五:在主配置声明映射关系
步骤六:在账务账号实体类中追加集合属性.
步骤七:测试

作业:写出多对一映射

hibernate的高级特性
二级缓存:二级缓存类似于一级缓存,可以缓存对象,但他是sessionFactory级别的缓存.
由sessionFactory负责管理,因此二级缓存的数据是共享的,不同的Session对象都可以共享二级缓存中的数据.

二级缓存适用场景
-对象数据频繁共享
-数据变化频率低

如何使用二级缓存
.导入ehcache.jar
.在src下添加缓存配置文件ehcache.xml
.在hibernate的主配置文件开启二级缓存,指定采用的二级缓存驱动类
.在要缓存的对象对应的映射关系文件中,开启当前对象的二级缓存支持并指定缓存策略.

--练习:
在查询员工时,使用二级缓存,使得不同的session可以共享这些员工的数据.
解决方案:
步骤一:导入二级缓存驱动包.
步骤二:引入二级缓存配置文件
步骤三:开启二级缓存,指定二级缓存驱动类.
步骤四:测试二级缓存
测试解决方案:
使用两个不同的session,查询同一条数据,查看控制台输出情况.


查询缓存.
.什么是查询缓存
查询缓存是依赖于二级缓存,可以理解为特殊的二级缓存,也会是sessionFactory级别的
,也是由sessionFactory负责维护.
查询缓存可以缓存任何查询到的结果.

.查询缓存以hql为key,缓存该hql查询到整个结果,即如果执行2次同样的hql,那么第二次执行时,
此次查询可以从查询缓存中取到第一次查询缓存的内容.


查询缓存的适用场景
频繁适用同样的sql做查询

如何使用查询缓存(三级缓存)
.开启二级缓存
.字hibernate.cfg.xml中开启查询缓存
.在查询代码执行前,指定开启查询缓存.

ps:使用hql语句进行全量查询,返回的结果不会放入一级缓存中
--练习:
在查询多条员工数据时,使用查询缓存,缓存查询的hql,使得再次使用同样的hql查询时不必重新访问数据库.

步骤一:开启二级缓存
上个案例已经完成,省略.查询缓存是基于二级缓存的,使用查询缓存的前提是开启二级缓存.
步骤二:开启查询缓存
步骤三:在查询代码执行前,指定开启查询缓存.
ps:查询缓存的key是hql的所对应的hql语句.

//清空查询缓存
HibernateUtil.sessionFactory.evictQueries();


------------------------------------------------------------------------------------------------------

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
    <!-- 数据库连接信息,根据自己的数据库进行配置 -->
        <property name="connection.username">system</property>
        <property name="connection.password">orcl</property>
        <property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
        <property name="connection.url">jdbc:oracle:thin:@localhost:1521:XE</property>
        <!-- Hibernate 的基本配置 -->
        <!-- Hibernate 使用的数据库方言 dialect方言,用于配置生成针对哪个数据库的sql语句.-->
        <property name="dialect">org.hibernate.dialect.OracleDialect</property>
        <!-- hibernate生成的sql语句是否输出到控制台 -->
        <property name="show_sql">true</property>
        <!-- 输出的sql语句否格式化  -->
        <property name="format_sql">true</property>
        
        <!-- 开启二级缓存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!-- 指定二级缓存驱动类 -->
        <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
        
        <!-- 开启查询缓存 -->
        <property name="hibernate.cache.use_query_cache">true</property>
        
        
        <!-- 声明映射关系文件  -->
        <mapping resource="com/sicheng/entity/Emp_h.hbm.xml"/>
        <mapping resource="com/sicheng/entity/Account.hbm.xml"/>
        <mapping resource="com/sicheng/entity/Service.hbm.xml"/>
        
        
    </session-factory>
</hibernate-configuration>
-------------------------------------------------------------------------------------------------------------

Account.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!-- 配置实体类和表的关系 -->
<hibernate-mapping>
<class name="com.sicheng.entity.Account" table="account">

<!-- 配置主键属性和字段的关系 -->
<id name="id" type="integer" column="id">
<!-- 指定主键的生成策略 -->
<generator class="sequence">
<!-- 指定用于生成主键的sequence -->
<param name="sequence">account_seq</param>
</generator>
</id>

<!-- 配置实体类中属性与表中字段的关系 -->
<property name="loginName" type="string" column="loginName"/>
<property name="loginPassword" type="string" column="loginPassword"/>
<property name="status" type="string" column="status"/>
<property name="createDate" type="date" column="createDate"/>

<!-- 配置services属性, 采用一对多关系-->
<set name="services">
      <!-- 指定关联条件,写关联条件的外键字段 -->
      <key column="account_id"/>
      <!-- 指定采用哪种关系,加载哪方数据 -->
      <one-to-many class="com.sicheng.entity.Service"/>
</set>

</class>
</hibernate-mapping>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值