1、 Hibernate
- 是连接Java应用程序和关系数据库的中间件;
- 对JDBC API进行了封装、负责Java对象的持久化;
- 在三层软件架构中它位于持久层(数据访问层),封装了所有数据访问细节,使业务逻辑层可以专注于实现业务逻辑;
- 它是一种ORM映射工具,能够建立面向对象的域模型和关系数据模型之间的映射。
- 是轻量级JavaEE应用的持久层解决方案。
2、 Hibernate框架的作用:
- Hibernate主要用来实现Java对象和数据的表之间的映射,除此之外还提供数据查询和获取数据的方法;
- Hibernate可以大幅度减少开发时手动编写sql语句和jdbc代码的时间;
- Hibernate可以完全隔离数据库,解耦项目与数据库的依赖关系;
- Hibernate的目标是简化开发者通常的数据持久化相关编程任务,解放其中的95%。
3、 PO(Persistent Object):持久化对象,是所有ORM框架中一个非常重要的媒介。PO的作用是完成持久化操作,即是通过该对象可对数据执行增删改查的操作,以面向对象的方式操作数据库。PO=POJO+XML映射文件。
4、 Hibernate操作步骤:
- 编写POJO;
- 编写POJO的映射文件(pojo类名.hbm.xml);
- 配置映射文件(hibernate.cfg.xml);
- 获取Configuration;
- 获取SessionFactory;
- 获取Session;
- 打开事务;
- 用面向对象的方式操作数据库;
- 关闭事务、关闭Session、关闭SessionFactory。
5、 Hibernate的持久化类的规则:
- 提供一个无参构造器;
- 提供一个标识属性,标识属性通常映射数据库表的主键字段。如果使用数据库表联合主键,需要自定义类,该类拥有联合主键类型的属性;
- 为持久化类的每个属性提供set/get方法;
- 持久化类必须是一个非final类;
6、 Hibernate的持久化对象状态:
- 瞬态:对象由new操作符创建,尚未与Session关联的对象被认为处于瞬态。瞬态对象不会被持久化到数据库中,也不会被赋予持久化标识。
- 持久化状态:持久化实例在数据库中有对应的记录,并拥有一个持久化标识。持久化对象必须与指定的Session关联。Hibernate会检测到处于持久化状态对象的改动,在当前操作执行完成时将对象数据写回数据库,开发者不用手动执行update更新数据库;
- 脱管状态:某个实例曾经处于持久化状态,但随着与之关联的Session被关闭,该对象就变成脱管状态。脱管对象的引用依然有效,对象可继续被修改。如果重新让脱管对象与某个Session关联,该对象将重新转换为持久化状态,而脱管期间的改动也可被写入数据库。
new可以创建瞬态对象,
瞬态——》持久化状态:save(),saveOrUpdate(),persist()
持久化状态——》脱管状态:evict(),close(),clear()
脱管——》持久化:update(),saveOrUpdate(),lock()
持久化——》瞬态:delete()
获得持久化状态对象:get(),load(),find()
7、 Session的方法
save(Obect obj,Object pk):将瞬态对象保存到数据库,并指定主键值;
persist(Object obj,Object pk);
save在保存持久化对象时,会返回持久化对象的标识属性(对应记录的主键值),而persist方法没有返回值。
load():用于加载一个持久化实例,即根据主键从数据库表中加载一条新记录,如果没有匹配数据库记录,load将会抛出异常;如果类映射文件中指定了延迟加载,load方法会返回一个未初始化的代理对象;
get():和load()方法类似,如果没有匹配数据库记录,会返回null,而不返回一个代理对象;
flash():刷新与Session关联的持久化对象,使与数据库保持同步;
对load方法和get方法加载的持久化实例进行修改,该修改将在Session的flush方法之前自动保存到数据库中,无需再做处理。
updateOrSave(Object obj):用于不清楚对象是否曾经持久化过,该方法会自动判断对象,如果持久化过,则调用update,否则调用save;
merge(Object obj):可将程序对脱管对象所做的修改保存到数据库,但与update方法最大的区别是merge方法不会持久化该对象,也就是说,执行merge方法仅是将对象的属性保存到数据库,对象本身仍然是脱管状态,不会被关联到Session上;
lock(Object obj,LockMode):用于将脱管状态的对象重新持久化,但该脱管对象必须没有修改过。lock方法可以搭配多种LockMode模式使用。
delete(Object obj):用于将持久化实例由持久化状态变为瞬态,同时该持久化实例对应的数据记录也会被删除;
映射文件的结构:
<hibernate-mapping><class><id><property></////> Hibernate默认开启延迟加载策略。
8、 Hibernate映射文件
映射主键:在项目开发过程中,建议不要使用具有实际意义的物理主键,而应该使用没有任何意义的逻辑主键。
映射普通属性:
- type:指定普通属性的数据类型,可以指定Hibernate基本类型名(如integer,string,character,date,timestamp,float,binary,object,blob等),也可以指定Java基本类型(如int,float,char,String,Date,Integer,Clob等);
- index:指定一个字符串的索引名称;
- length:指定该属性所映射数据列的字段长度;
- precision:指定该属性所映射数据列的有效数字位的位数;
- scale:指定该属性所映射数据列的小数位数;
9、映射集合属性:
一种是List、Set或数组等集合属性;一种是Map结构;
- Hibernate要求持久化集合值字段必须声明为接口;
- 集合类实例具有值类型的行为,当持久化对象被保存时,这些集合属性会被自动持久化;当持久化对象被删除时,这些集合属性对应的记录将被自动删除;如果集合元素被从一个持久化对象传递到另一个持久化对象,该集合元素对应的记录也会从一个表转移到另一个表;
- 两个持久化对象不能共享一个集合元素的引用;
bag元素映射:
<bag>元素可以映射List集合属性,也可以映射Set集合属性,甚至可以映射Collection集合属性。无论是哪种集合属性,使用<bag>元素都将被映射成无序集合,集合属性对应的表没有主键。
映射Map集合属性
Hibernate对List集合的属性使用<map>元素进行映射,当配置<map>元素时也需要使用<key>子元素映射外键列,除此之外,Map集合属性还需要映射Map Key。
Hibernate将以外键列和Key列作为联合主键。
order-by=”字段 desc”按顺序查询
可以为单个集合元素设置lazy=”false”
有序集合的属性在增、删、改、查数据库操作中性能表现良好。
集合属性表里的记录完全“从属”于主表,当主表的记录被删除时,集合属性表里“从属”与该记录的数据将会被删除。Hibernate无法直接加载、查询集合属性表中的记录,只能先加载主表,再通过主表获取集合属性对应的记录。
映射组件属性:
所谓组件属性是指持久化类的属性,并不是基本数据类型,而是一个复合类型,在持久化的过程中,它仅仅被当作值类型,而并非引用另一个持久化实体。
Hibernate使用<component>元素映射组件属性,每个<component>元素映射一个组件属性。除此之外,还需要使用<parent>子元素映射组件类内一个指定其容器实体的引用。
如果组件的属性是基本类型,使用<property>子元素映射;
如果组件的属性是组件类型,使用<nested-composite-element>子元素映射这些嵌套组件属性;
如果组件的属性引用其他持久化实体,使用<many-to-one>子元素映射;
联合主键映射:
Hibernate允许直接将持久化类的多列映射称为联合主键,但需要满足如下两个要求:
实现Serializable序列化接口;
根据联合主键列所映射的属性来重写equals()方法和hashCode()方法。
常用Hibernate annotation标签:
@Entity 声明该类为持久类;
@Table(name=”promotion_info”)
@Id,@GeneratedValue,@Version,@Transient,@Enumerated,@OrderBy,@Formula
Hibernate关联映射
关联关系:客观世界中的对象往往是相互关联的,关联关系是面向对象分析和面向对象设计最重要的内容,Hibernate完全可以理解这种关联关系,并进行关联映射。关联关系一般分为两类:单向关联和双向关联。
双向多对一关联时,习惯由多的一方来控制,即inverse=”false”,将少的一方设置为inverse=”true”。
双向多对多关联只能采用连接表来建立两个实体之间的关联关系(即将多对多转化为两个一对多关系)。
实际项目开发中,并不推荐使用复合主键,建议采用没有物理意义的逻辑主键,符合主键的做法不仅会增加数据库建模的难度,而且增加关联关系的维护成本。
组件属性默认启动级联操作,关联映射默认不会启动级联操作。
Hibernate继承映射有三种策略:
<subclass>,<joined-subclass>,<union-subclass> 在这种映射策略下,既不需要使用辨别者列,也无需使用<key>元素来映射共有主键。注意:使用union-subclass映射策略不能使用identity主键生成策略,也不能使用native。
HQL是一种面向对象的查询语言。SQL的操作对象是数据表、列和记录,而HQL的操作对象是类、实例和属性。
HQL查询基本步骤:
- 获取Session对象;
- 编写HQL语句;
- 以HQL语句作为参数,调用Session的createQuery方法创建Query查询对象;
- 调用Query查询对象的list方法返回查询结果列表(持久化对象集合);
from子句:
from是最简单的HQL语句,其后紧跟持久化类的类名;
HQL语句本身不区分大小写,但HQL语句中所使用的包名、类名、实例名、属性名都区分大小写。
select子句:
select用于选择持久化类的实例或持久化类指定的属性;
占位符:
使用英文问号(?) 使用冒号+名字(:name)
Query有两个方法支持查询实现分页功能:setFirstResult(int firstResult)、setMaxResults(int maxResults)
联表查询:Hibernate使用关联映射来处理底层数据表之间的连接。
HQL支持两种关联连接方式:隐式关联连接和显示关联连接。
- 隐式连接底层将转换为SQL的交叉连接(笛卡尔乘积),显示连接将转换为SQL的多表连接(内连接、左外连接等);
- 隐式连接查询返回的是多个被查询实体组成的集合;显示连接查询返回的结果也是集合,但是集合元素是被查询持久化对象,所有被关联的持久化对象所组成的数组;
fetch关键字:
对于持久化类有集合属性的情况,Hibernate默认采用延时加载策略,不加载集合属性,解决办法有两个,1:配置指定lazy=”false” 关闭延迟加载2:在HQL语句中通过添加fetch关键字抓取持久化类的集合属性;
命名查询:getNamedQuery(“”),在对应的类的xml里进行配置。
条件查询:利用Session创建criteria对象,通过该对象.add(Restrictios.条件),然后criteria.list()获得查询结果集合。
SQL查询:用于将旧的项目(如基于JDBC应用)移植到Hibernate应用上;用于HQL无法支持的某些数据库的特性上。
对于一个新的Hibernate应用,建议不要直接使用SQL查询,应该更多使用HQL。
过滤器:Hibernate默认不启动过滤器。
缓存机制:
Session级别的一级缓存(默认开启):在Session关闭时调用flush,将缓存中的数据更新到数据库,减少数据库操作,提高性能
SessionFactory级别的二级缓存(默认关闭):是全局性的,应用的所有Session都共享二级缓存,当程序开放二级缓存时,Session需要获取数据时,会优先从二级缓存获取。
<property name=”hibernate.cache.use_second_level_cache”>true</property>
Hibernaete 悲观锁、乐观锁机制:
数据库并发性:指多个事务可以同时访问数据库中的数据。而当多个事务在数据库中并发执行时,数据的一致性可能受到破坏,从而导致数据出现问题。
悲观锁:即某事务在更新数据过程中将数据锁定,其它任何事务都不能读取或修改,必须修改完成后才能访问数据(类似于java的线程同步机制);
特点:具有排他性,通常依赖于数据库机制;
适用场景:一般适合短事务处理;
使用:如果需要使用悲观锁,通常采用数据库的for update语句,Hibernate使用load()方法设置悲观锁。
注意:如果使用悲观锁,那么延时加载无效。
乐观锁:乐观锁并不是一种锁机制,而是一种冲突检测机制;
特点:并发性较好,事务修改数据时,其它事务仍可以修改数据;
使用:常用的是版本方式(即每个数据表中有一个版本字段version,某一个事务更新后版本号+1,另一个事务更新后再+1,当事务发现数据库当前版本号与数据读取时版本号不一致(等于或小于数据库当前版本号)则不能更新数据)。
开启乐观锁:在映射文件中配置对应项,optimistic-lock=”version”
注意:添加的版本字段version由Hibernate负责维护。
Hibernate性能优化:
批处理:手动调用Session的flush()和clear()方法,将一级缓存写入到数据库中然后清空。另外注意需关闭SessionFactory的二级缓存。
延迟加载:可分为三类:对象的延时加载;对象里的属性延时加载;集合延时加载;
Hibernate通过代理(Proxy)机制来实现延时加载。