A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

Hibernate

框架是什么
1.框架是用来提高开发效率的
2.封装了一些功能,我们需要使用这些功能时,调用即可,不需要手动实现
3.框架可以理解成一个半成品的项目,只需要懂得如何使用这些功能即可

Hibernate是什么
Hibernate是一个对JDBC进行封装的轻量级的ORM框架

什么是ORM
对象关系映射(Object Relational Mapping,简称ORM)
是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术
ORM是通过使用描述对象和数据库之间映射的元数据,将Java程序中的对象自动持久话到关系数据库中
本质上就是从一种形式转换到另一种形式

优点
操作数据库时,可以以面向对象的方式来完成,不需要书写sql语句

ORM分四级
        Hibernate属于四级:完全面向对象操作数据库
        mybatis属于二级
        dbutils属于一级
       
映射文件
映射配置文件主要是用于描述实体类与数据表之间的映射关系
位置要与实体类在同一个包下
名称:类名.hbm.xml
约束:Hibernate核心包下的org.hibernate包下的hibernate-mapping-3.0.dtd文件中查找
注意:配置文件中的实体类名和字段名称都区分大小写,要与实体类文件保持一致.
在实际开发过程中,要指定属性字段的长度,并且长度要与数据库表中的字段长度相对应
如果属性字段名称与表中字段名称不一致,最好用column指定对应表中的字段名称
约束:
-----------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
--------------------------------------------------------------------------
详细配置
<!-- package统一声明包名,在class中就不用写类的全名 -->
<hibernate-mapping package="cn.itheima.domain">
        <!-- name属性它是实体类的全名 table 表的名称 catalog 数据库名称 -->
        <class name="Customer" table="t_customer"
                catalog="hibernateTest">
                <!-- id它是用于描述主键 -->
                <id name="id" column="id" type="int">  <!-- java数据类型 -->
                        <!-- 主键生成策略 -->
                        <generator class="native"></generator>
                </id>
               
                <!-- 使用property来描述属性与字段的对应关系 -->
                <property name="name" column="name" length="20" type="string"></property>  <!-- hibernate数据类型 -->
                <property name="address">
                        <column name="address" length="50" sql-type="varchar(50)"></column> <!-- sql数据类型 -->
                </property>
                <property name="sex" column="sex" length="20"></property>
        </class>
</hibernate-mapping>

核心配置文件
主要是hibernate框架使用主要包含连接数据库相关信息,hibernate相关配置等
位置要在src下创建一个hibernate.cfg.xml
约束:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
----------------------------------------------------------------------------
----------------------------------------------------------------------------
相关配置
<hibernate-configuration>
        <session-factory>
                <!-- 配置关于数据库连接的四个项 driverClass url username password -->
                <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
                <property name="hibernate.connection.url">jdbc:mysql:///hibernateTest</property>
                <property name="hibernate.connection.username">root</property>
                <property name="hibernate.connection.password">root</property>
                <!-- 设置连接提供者 -->
                <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
                <!-- c3p0连接池的配置 -->
                <property name="hibernate.c3p0.max_size">20</property> <!-- 最大连接池 -->
                <property name="hibernate.c3p0.min_size">5</property> <!-- 最小连接数 -->
                <property name="hibernate.c3p0.timeout">120</property> <!-- 超时 -->
                <property name="hibernate.c3p0.idle_test_period">3000</property> <!-- 空闲连接 -->
                <!-- 可以将向数据库发送的sql显示出来 -->
                <property name="hibernate.show_sql">true</property>
                <!-- 格式化sql -->
                <property name="hibernate.format_sql">true</property>
                <!-- hibernate的方言 -->
                <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
                <!-- 自动创建表 -->
                <property name="hibernate.hbm2ddl.auto">update</property>
                <!-- 用于设置事务提交方式 -->
                <property name="hibernate.connection.autocommit">false</property>
                <!-- 配置hibernate的映射文件所在位置 -->
                <mapping resource="cn/itheima/domain/Customer.hbm.xml" />
        </session-factory>
</hibernate-configuration>       

<property name="hibernate.hbm2ddl.auto"></property>属性配置
create-drop每次都会创建一个新表,执行完后删除,一般在测试中使用
create 每次都会创建一个表.一般在测试中使用
upfate 如果数据库中有表,不创建,没有表创建,如果映射不匹配,会自动更新表结构(只能添加)
vakidate 只会使用存在的表,并且会对映射关系进行校验

hibernate工作原理:
1、通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件。
2、由hibernate.cfg.xml中的<mapping resource="xx/xx/xxx.hbm.xml"/>读取解析映射信息。
3、通过config.buildSessionFactory();//得到sessionFactory。
4、sessionFactory.openSession();//得到session。
5、session.beginTransaction();//开启事务。
6、persistent operate;
7、session.getTransaction().commit();//提交事务
8、关闭session;
9、关闭sessionFactory;

SessionFactory介绍
首先SessionFactory是通过Configuration得到
SessionFactory接口负责初始化hibernate.他充当数据储存源的代理,负责创建Session对象,这里用到了工厂模式.
需要注意的是SessionFactory并不是轻量级的因为一般情况下,一个项目通常只需要一个SessionFactory就够,
但操作多个数据库时可以为每个数据库指定一个SessionFactory.

Query简介
Query接口方便对数据库及持久对象进行查询,它可以有两种表达方式:
HQL语句或本地数据库的SQL语句
Query经常被用来绑定查询参数.限制查询记录数量,并最终执行查询操作
执行hql语句.
Query query=Session.createQuery(hql);
执行sql语句
SQLQUery sqlQuery=Session.createSQLQuery(sql);
想要执行本地sql要使用addEntity方法将结果封装到指定对象中,如果不封装,得到的是list集合

Query上的list()和iterate()方法
list方法在读取数据时,并不会利用缓存,而是直接向数据库查询,
iterate将读取的数据写到缓存,并用于读取时再次利用

hibernate中持久化类介绍
Persistent Object  (PO)
持久化是将程序数据在持久状态和瞬时状态转换的机制
持久化类是指是指他的实例可以呗hibernate持久化的保存到数据库中,并能从数据库中读取的类
持久化类=实体类+映射文件

hibernate中持久化类的编写规则
1        提供一个无参数public访问控制符的构造器,因为会用到反射
2        提供一个属性标识,映射数据表主键字段OID
        Java区分两个对象是否是同一个对象,使用地址判断
        数据库区分两条记录是否一致,使用主键判断
        hibernate区分持久化对象是否为同一个对象,根据唯一标识
3        为所有属性提供public访问控制符的set/get方法,框架中存值和取值使用
4        标识符应尽量使用基本数据类型的包装类型
5        持久化类不要用final进行修饰
        用final修饰的类不能被继承,因为无法生成代理对象,由于延迟加载返回的是代理对象
        因此延迟加载就会失效

OID的作用
指的是与数据库中的主键对应的属性,
hibernate框架他是通过OID来区分不同的PO对象,
如果在内存中有两个相同的OID对象,那么hibernate认为他们是同一个对象

Hibernate中 get和load区别:
get是立即加载,load是延迟加载
hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,
如果在使用过程中发现了问题,只能抛异常;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。

hibernate主键生成策略
increment
        由hibernate维护一个变量每次生成主键时自增
        问题:如果有多个应用访问一个数据库,由于每个应用维护自己的主键,会反生主键冲突
        不适合高并发访问
identity
        由数据库底层生成标识符,条件是数据库支持自动增长数据类型
        mysql支持,oracle不支持
sequence
        hibernate根据底层数据库序列生成标识符,条件是数据库支持序列
        优点:由底层数据库维护,和hibernate无关
native
        根据底层数据库对自动选择
        由于生成数据库主键策略由hibernate控制,不建议使用
        优点:在项目中使用多个数据库时使用
uuid
        hibernate采用128bit位的UUID算法来生成标识符
        优点:与数据库无关,方便数据移植效率高,不访问数据库就能生成主键
        缺点:长度为32位,占用空间比较大
assigned
        自然主键,不建议使用

持久化对象的三种状态
        瞬时态:由new命令开辟的内存空间的Java对象
        持久态:处于该状态的对象在数据库中具有相应的记录,并拥有一个持久化标识
        游离态:也叫托管态,当与持久对象关联的Session被关闭后,该持久对象就会变成游离态
       
session缓存
1.Session级别的缓存,它同session绑定。它的生命周期和session相同。Session销毁,它也同时销毁;管理一级缓存,一级缓存无法取消,用两个方法管理,clear(),evict()。
2.两个session不能共享一级缓存,因为它会伴随session的生命周期的创建和销毁;
3.Session缓存是实体级别的缓存,就是只有在查询对象级别的时候才使用,如果使用HQL和SQL是查询属性级别的,是不使用一级缓存的!切记!!!!
4.iterate查询使用缓存,会发出查询Id的SQL和HQL语句,但不会发出查实体的,它查询完会把相应的实体放到缓存里边,一些实体查询如果缓存里边有,就从缓存中查询,但还是会发出查询id的SQL和HQL语句。如果缓存中没有它会数据库中查询,然后将查询到的实体一个一个放到缓存中去,所以会有N+1问题出现。
5.每一个Hibernate Session实例和一个数据库事务绑定,就是说,每执行一个数据库事务(操作),都应该先创建一个新的Hibernate Session实例。
如果事务执行中出现异常,应该撤消事务.不论事务执行成功与否,最后都应该调用Session的close()方法,从而释放Hibernate Session实例占用的资源。

一级缓存特点
        当通过session的save,update,saveOrUpdate进行操作时,如果一级缓存中没有对象
        会将这些对象从数据库中查询到,储存到一级缓存中
        当通过session的load,get,Query,的list等方法进行操作时,会先判断一级缓存中是否存在,如果没有才会从数据库中获取
        并且将查询的数据储存到一级缓存中,而list不利用缓存中的数据
        当调用session的close方法时,session缓存被清空
       
常见的操作
1.flush
修改一级缓存数据,针对内存操作,需要在session执行flush操作时,将缓存变化同步在数据库,而只有在缓存数据与快照区不一致的时候,才会生成update语句。
2.clear
清除所有对象的一级缓存,对对象所做的修改,全部都没有了,跟当初的快照一样。
3.evict
清除一级缓存指定对象。将指定的持久化对象从缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象。
4.refresh
重新查询数据库,更新快照和一级缓存。
5.Session手动控制缓存
在hibernate中也为 我们提供了手动控制缓存的机制,具体如下
        Always:每次查询时,session都会flush
        Auto:有些查询时,session会默认flush,例如commit。session.flush
        Commit:在事务提交的时候
        Manual:只有手动调用sessionflush才会刷出

hibernate关联映射,一对多
映射方式,配置文件中:
        在一的一方的集合上采用<key>标签,在多的一方加入一个外键
        在多的一方采用<many-to-one>标签
配置详情:
name="对应本类的属性名"
column="映射到本表的字段名"
class="映射到本表的实体类"
unique="ture|false":(数据库外键字段生成一个唯一约束)
not-null="ture|false"默认false(数据库外键字段是否允许为空值)
lazy="ture|false"默认proxy(延迟加载)

级联保存
        在多的一方<many-to-one>标签中添加属性,cascade="save-update"
        在一的一方<set>标签中添加属性,cascade="save-update"

关于cascade(级联)属性
级联的意思是指定两个对象之间的操作联动关系,对一个对象执行了操作之后,对其指定的级联对象也需要执行相同的操作。
总共可以取值为:all、none、save-update、delete
all-代表在所有的情况下都执行级联操作
none-在所有情况下都不执行级联操作
save-update-在保存和更新的时候执行级联操作
delete-在删除的时候执行级联操作
delete-orphan 删除与当前对象解除关系的对象。
all-delete-orphan 它包含了delete-orphan与all操作。

cascade与inverse有什么区别?
1)cascade它是完成级联操作;
2)inverse它只有在双向关联情况下有作用,它来指定由哪一方维护外键。

hibernate注解开发
PO类注解-基本设置
@Entity--将一个类声明为一个实体bean
@Table--注解声明了该实体bean映射指定的表(table),目录(catalog),schema的名字
@Id--注解声明了该实体bean的标识属性(对应表中的主键)
@GeneratedValue--注解声明了主键的生成策略
        GenerationType.AUTO?主键由程序控制;
        GenerationType.TABLE?使用一个特定的数据库表格来保存主键;
        GenerationType.IDENTITY?主键由数据库自动生成(主要是自动增长类型);
        GenerationType.SEQUENCE?根据底层数据库的序列来生成主键,条件是数据库支持序列。(这个值要与generator一起使用);
        --------
        使用UUID生成策略
        @GenericGenerator(name="myuuid",strategy="uuid")
        @GeneratedValue(generator="myuuid")
        -------
@Column--注解声明了属性到列的映射
@SequenceGenerator--注解声明了一个数据库序列
@GenericGenerator--注解声明了一个hibernate的主键生成策略
@Temporal--声明日期类型
@Transient配置瞬时的,不要跟数据库对应,指定的属性不需要持久化,即不再表中生成

注解开发-一对多关联关系【掌握】
        @ManyToOne 设置多对一关联
        optional:是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true?
        fetch:表示抓取策略,默认为FetchType.EAGER?
        cascade:表示默认的级联操作策略,可以指定为ALL,PERSIST,MERGE,REFRESH和REMOVE中的若干组合,默认为无级联操作?
        targetEntity:表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity。
        @OneToMany 描述一个一对多的关联
        该属性应该为集体类型,在数据库中并没有实际字段。
        fetch:表示抓取策略,默认为FetchType.LAZY,因为关联的多个对象通常不必从数据库预先读取到内存。
        cascade:表示级联操作策略,对于OneToMany类型的关联非常重要,通常该实体更新或删除时,其关联的实体也应当被更新或删除
        例如:实体User和Order是OneToMany的关系,则实体User被删除时,其关联的实体Order也应该被全部删除

hibernate检索方式介绍
1.导航对象图检索方式,根据已加载的对象导航到其他对象
2.OID检索方式,按照对象的OID来检索对象
3.HQL检索方式,使用面向对象的HQL查询语言
4.QBC检索方式,使用QBC API来检索对象,这种API封装了字符串形式的查询语句,提供了更加面向对象的查询接口
5.本地的SQL检索方式,使用本地数据库的SQL查询语句

Hql多表操作分类:
1.交叉连接
2.内连接
a)显示内连接
b)隐式内连接
c)迫切内连接
3.外连接
左外连接
迫切左外连接
右外连接
注意:在hibernate中有迫切连接的概念,而sql中没有。

事务介绍
问题:什么是事务?
        事务就是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全都失败。
问题:事务四个特性?
        原子性:不可分割
        一致性:事务在执行前后,要保证数据的一致。
        隔离性:一个事务在执行的过程中,不应该受到其它事务的干扰。
        持久性:事务一旦结束,数据持久化到数据库。
问题:不考虑事务的隔离性,会产生什么问题?
        脏读:一个事务读取到另一个事务的未提交数据
不可重复读:一个事务读取到另一个事务提交的数据(主要是指update),会导致两次读取的结果不一致。
虚读(幻读): 一个事务读取到另一个事务提交的数据(主要是指insert),会导致两次读取结果不一致.
问题:对于上述问题如何解决?
        我们可以通过设置隔离级别来解决.
        READ_UNCOMMITED 读取未提交,它引发所有的隔离问题
        READ_COMMITTED  读已提交,阻止脏读,可能发生不可重复读与虚读.
        REPEATABLE_READ 重复读  阻止脏读,不可重复读 可能发生虚读
        SERIALIZABLE 串行化 解决所有问题 不允许两个事务,同时操作一个目标数据。(效率低下)

Hibernate中设置事务隔离级别
hibernate.connection.isolation
它可取的值有 1 2 4 8
1代表的事务隔离级别为READ UNCOMMITTED
2代表的事务隔离级别为READ COMMITTED
4.代表的事务隔离级别为 REPEATABLE READ
8代表的事务隔离级别为 SERIALIZABLE
<property name="hibernate.connection.isolation">4</property>

Hibernate提供了三种管理session的方式:
1.Session对象的生命周期与本地线程绑定(ThreadLocal)
2.Session对象的生命周期与JTA事务绑定(分布式事务管理)
3.Hibernate委托程序来管理Session的生命周期

HQL优化
1.使用参数绑定
        1.使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
        2.避免SQL注入
2.尽量少使用NOT
        如果where子句中包含not关键字,那么执行时该字段的索引失效。
3.尽量使用where来替换having
        Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
4.减少对表的查询
        在含有子查询的HQL中,尽量减少对表的查询,降低开销
5.使用表的别名
        当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
6.实体的更新与删除
        在hibernate3以后支持hql的update与delete操作

set上的fetch与lazy
set上的fetch与lazy它主要是用于设置关联的集合信息的抓取策略。
Fetch可取值有:
1.SELECT 多条简单的sql   (默认值)
2.JOIN 采用迫切左外连接
3.SUBSELECT 将生成子查询的SQL
lazy可取值有:
1.TURE 延迟检索   (默认值)
2.FALSE 立即检索
3.EXTRA 加强延迟检索(及其懒惰)





0 个回复

您需要登录后才可以回帖 登录 | 加入黑马