Hibernate入门
Posted wuba
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate入门相关的知识,希望对你有一定的参考价值。
Hibernate:是一持久层的ORM的框架,能够减轻dao层的编码
ORM:Object Relational Mapping(对象关系映射)能够将java中对象与关系型数据库中的表建立联系,操作java对象即可对操作数据库中的表
一:建立类与表的映射
二:配置Hibernate核心文件
三:核心API
1:Configuration:加载hibernate核心配置文件
加载hibernate.properties :Configuration cfg=new Configuration();
但通常是加载hibernate.cfg.xml :Configuration cfg=new Configuration().configure();
2:SessionFactory:Session工厂
SessionFactory内部维护了hibernate连接池和hibernate二级缓存,线程安全,一个项目只需一个SessionFactory
3:Session:此时指的是hibernate里的session,线程是不安全的(应放在方法内部调用)是与数据库连接的桥梁
API:1)保存
Serializable save(Object object) 返回一个相对应的ID
2)查询
Object get(Object.class,Serializabel ID)
Object load(Object.class,Serializabel ID)
get与load查询的区别:
a:get方法执行到查询语句后立即发出sql语句查询,load查询执行时不会立即发出sql语句,在逼不得已需要使用时才会查询(lazy,懒查询)
b:get查询后返回的是对象本身,load查询返回的是代理对象,利用javassist产生代理
c:get查询查不到时会返回null,load查询查不到时返回ObjectNotFoundException
3)更新
void update(Object object)
4)删除
void delete()
5)查询一个表的所有数据
4:Transaction,事务,以后主要交给Spring
主要API commit() 提交事务 rollback( )回滚事务
四:持久化类编写规则
持久化类=类+映射文件 ,将java对象与数据库的表建立联系,使数据可以存储再数据库中(硬盘里)
1,类中的属性私,且尽量用引用数据类型(包装类型修饰)提供get,set方法
2,类不要用final修饰,如果用final修饰,则不能被继承,影响延迟加载如load()查询会与get()变得一样
3,提供无参构造方法,hibernate底层会利用发射创建类的实例对象
4,对持久化类提供一个唯一表示OID与数据库主键对应,hibernate底层通过该ID来识别是否时同一个对象
五:主键的生成策略
1,主键的分类
自然主键:主键是表字段的一部分,如身份证表利用身份证号充当主键
代理主键:主键不属于表字段 ,一般建议用代理主键,可以在不更改源码的情况下扩展
2,Hibernate中主键的生成策略
1)increment,适用于int,short,long 的主键,hibernate中提供的自动增长机制,在单线程中使用,首先发送一条sql语句,select max(id) from 表,然后id+1
2)identity ,使用于int,short,long,由数据库底层提供的自动增长机制,使用于MySQL等
3)sequence,适用于short,int,long,采用序列方式,使用于Oracle数据库,mysql不使用
4)uuid,适用于String 类型,由hibernate提供随机字符串
5)native ,本地策略,可以在identity和sequence来回切换,区别于用啥数据库
6)assigned,需要手动编写程序或是用户自己设置,hibernate放弃外键的管理
六:持久化类的三种状态
1:三种状态之间的转换
2:主要了解持久化对象 -对象有OID标识,且被session接管
特点:持久化类处于持久态时,更新的数据可以自动存到数据库中
底层依赖于Hibernate一级缓存
七:Hibernate缓存
缓存:将数据或对象放入内存中,不直接通过硬盘
作用:降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。
hibernate缓存分为两个级别,一级缓存(自带)和二级缓存(需要配置,一般不常用),用Redis代替
一级缓存:
Session级别的缓存,生命周期与session同步,由session中一系列数组组成
数据放入缓存:
1. save()。当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中。
2. get()和load()。当session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。
3. 使用HQL和QBC等从数据库中查询数据。
证明一级缓存的存在:
测试demo运行结果:
Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?)
true
数据从缓存中清除:
1. evit()将指定的持久化对象从缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象。
2. clear()将缓存中的所有持久化对象清除,释放其占用的内存资源。
其他缓存操作:
1. contains()判断指定的对象是否存在于缓存中。
2. flush()刷新缓存区的内容,使之与数据库数据保持同步。
一级缓冲区中的结构:
里面有很多的map,map的key,和value分别为缓存区,和快照区,当在持久态时更新数据并提交事务时,数据提交到缓冲区后,会与快照区的数据进行对比,如果一样快照区不变,如果不同,则会将更改的数据自动更新到数据库中
注意:
一个session不能取另一个session中的内容
二级缓存:
SessionFactory级别的缓存,可以跨越Session存在,可以被多个Session所共享。
详细参考:http://www.cnblogs.com/200911/archive/2012/10/09/2716873.html
八:Hibernate的事务管理
事务的特性:
原子性:事务是一个不可分割的工作单位,要么发生,要么不发生
一致性:一个事务中,事务前后数据的完整性必须一致
隔离性:多个事务之间互不干扰
持久性:事务一旦被提交,提交到数据库中的数据就是永久性的
并发问题:脏读,不重复度,虚度/幻读
解决并发:设置隔离级别
read uncommitted(无法解决问题)
read committed(解决脏读,oracle默认隔离级别)
repeatable read(解决不重复读和脏读,mysql默认隔离级别)
serializable(都可以解决,但是相当与一个锁表,不能多个客户端向数据库写入数据)
在hibernate核心文件中配置hibernate事务隔离级别
事务主要是作用在Service层,确保session是同一个,需要调用SessionFactory中的getCurrentSession()方法
在hibernate核心配置文件中配置
测试
九:Hibernate的其他API
1,Query :通过Session session 获得
通过HQL(hibernate query language)的面向对象的查询
2,Criteria:也是通过Session session获得
QBC(query by criteria)适用于条件查询,更加倾向面向对象查询
3:SQLQuery 通过sql语句查询
十:Hibernate中表于表之间的关系,配置
1,表于表之间的关系
一对多:在多的一方添加一的一方的主键为外键,在一的一方实体放入多的实体的集合,在多的一方实体放入一的一方的对象
多对多:建立一个中间表,至少将两个多对多的表的主键充当字段
一对一:实现是可以其中一表唯一外键或是两个表主键对应
详细参考:https://blog.csdn.net/ago52030/article/details/1721033
2,hibernate中一对多的映射配置:(配置完成后需要将映射文件引入核心配置文件中)
多的一方表的映射配置:
一的一方映射配置:
Hibernate一对多关系的级联设置
级联:对一个对象进行保存或更新,如果对象关联了其他对象,这会一同改变
一的一方进行级联配置:
多的一方进行级联配置:
对象导航:只要两边映射文件都配置了级联,则只要互相设置了关联,只需要保存一方,另一方一会保存
级联删除:(多用于一的一方级联删除多的一方,先查询,再删除)
首先需要在一的一方映射文件配置:
测试级联删除:
让一的一方放弃外键的维护
在一的一方的映射配置文件里设置 inverse="true" ,默认为false,可以避免产生多余的sql语句
注意:一的一方放弃外键维护后,级联保存或更新一的一方,多的一方的外键无法随之更改,此时应级联操作多的一方
3:Hibernate中多对多表的实体创建和映射配置
例子:Role(角色表)于User(用户表)为多对多的关系,需要一个中间表
1,在两个表的实体里面分别创建对方对象的SET集合
2,在两个表的映射文件里配置相互关系(以下只给出User映射文件的配置,Role表一样)
3,之后将两个表的映射文件映入hibernate核心配置文件里
注意:两个多对多的表设置了相互关联后,需要其中一表放弃外键维护,一般是被动(被选)的表放弃,在其映射文件里设置inverse="true",该例子中被选表是Role(角色表)
4,多对多的级联删除(基本不用)
5,一般进行User表对Role表的增删改,是对集合的操作
十一:Hibernate的查询方法
1,OID查询
session.get() , session.load()
2,对象导航查询
根据OID查询到的对象的基础上级联查询
例:Customer customer =Session.get(LinkMan.class,1l).getCustomer();
List<LinkMan> list=Session.get(Customer.class,1l).getLinkmans();
3,HQL(Hibernate Query Language)查询
简单查询所有:上面写过
排序查询:
asc(升序)默认, desc(降序)
条件查询:
投影查询&分页查询:
聚合函数查询&分组查询:
4,QBC(Query By Criteria)更加面向对象的查询
简单查询所有:上面写过
排序查询:
分页&条件查询:
聚合条件查询&group by having
DetachedCriteria:离线条件查询(现阶段简单实现)
6:HQL的多表查询
SQL多表查询:https://baijiahao.baidu.com/s?id=1598467381137881566&wfr=spider&for=pc
Hibernate内连接:
Hibernate外连接:
7,SQL语句查询
利用sql语句查询
十二:Hibernate的抓取策略
1,延迟加载:lazy(懒加载)原理是使用动态代理,执行到相关语句时不会立刻发送sql语句,到真正需要时才会发送
类级别的延迟加载
在持久类映射文件的<Class lazy="true" /> 上设置的延迟为类级别,默认为true
如何让lazy失效?
1)设置 lazy="false"
2) 持久类用final修饰,让其无法继承接口,则无法实现动态代理
3)Hibernate initialize(Object object)
关联级别的延迟加载
查询获取的对象后,查询其关联的对象是否采用延迟加载
可以在映射文件的关联设置里 <set lazy="true" /> 或是<many-to-one lazy="true" />设置延迟
2,抓取策略:
什么叫抓取策略:通过获取的对象抓取其关联的对象,需要发送sql语句查询,如何发送,是否加载延迟,以达到尽可能的优化
通过在<set /> 和<many-to-one />上设置 fetch 属性值,用于控制发送的sql语句的格式的,,搭配 lazy 属性值来达到抓取策略
<set />上fetch,lazy的设置:
fetch:select,join,subselect --控制发送sql的格式
lazy:true,false,exroa(最懒级别,查什么就只发送相关的sql语句)--控制延迟
一般开发都采用默认级别,即 fetch="select" lazy="true" 偶尔会采用fetch="join"
如果lazy="false". fetch="select" 或“subselect" 会一次性的发送所需要的sql语句,而不是延迟发送
当fetch="join"时,,一次性发送一条sql语句,此时lazy设置什么属性都无所谓
<many-to-one>上fetch,lazy的设置:
fetch:select,join(为迫切左外连接)
lazy:proxy,false,noproxy(基本不用)
常采用默认值:fetch="select" lazy="proxy" --其的取值于一的一方<Class lazy="" />的取值相关联 偶尔会采用fetch="join"
3:批量抓取(减少发送的sql语句,提供效率)
例子:Customer 与 LinkMan的一对多的关系
以上是关于Hibernate入门的主要内容,如果未能解决你的问题,请参考以下文章