hibernate简介

hibernate 简介

hibernate是一个开源框架,它是对象关联关系映射的框架,它对JDBC做了轻量级的封装,使java程序员可以使用面向对象的思想来操纵数据库。

hibernate核心接口

  • session:负责被持久化对象CRUD操作
  • sessionFactory:负责初始化hibernate,创建session对象
  • configuration:负责配置并启动hibernate,创建SessionFactory
  • Transaction:负责事物相关的操作
  • Query和Criteria接口:负责执行各种数据库查询

    hibernate工作原理:

  1. 通过Configuration config = new Configuration().configure();//读取并解析hibernate.cfg.xml配置文件
  2. 由hibernate.cfg.xml中的读取并解析映射信息
  3. 通过SessionFactory sf = config.buildSessionFactory();//创建SessionFactory
  4. Session session = sf.openSession();//打开Sesssion
  5. Transaction tx = session.beginTransaction();//创建并启动事务Transation
  6. persistent operate操作数据,持久化操作
  7. tx.commit();//提交事务
  8. 关闭Session
  9. 关闭SessionFactory

    为什么要用hibernate:

  10. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层(DAO层)繁琐的重复性代码。
  11. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
  12. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
  13. hibernate映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

    Hibernate的查询方式

    HQL、Criteria,本地sql 查询
    HQL:
  14. 属性查询
  15. 参数查询、命名参数查询
  16. 关联查询
  17. 分页查询
  18. 统计函数

    如何优化Hibernate?

    1.使用双向一对多关联,不使用单向一对多
    2.灵活使用单向一对多关联
    3.不用一对一,用多对一取代
    4.配置对象缓存,不使用集合缓存
    5.一对多集合使用Bag,多对多集合使用Set
    6.继承类使用显式多态

hibernate的开发步骤:

开发步骤

  1. 搭建好环境

    • 引入hibernate最小的jar包
    • 备Hibernate.cfg.xml启动配置文件
  2. 写实体类(pojo== entity)

  3. 为实体类写映射文件”User.hbm.xml”或者jpa 注解

    • 在hibernate.cfg.xml添加映射的实体
  4. 创建库表

  5. 写测试类

    • 获得Configuration
    • 创建SessionFactory
    • 打开Session
    • 开启事务
    • 使用session操作数据
    • 提交事务
    • 关闭资源

      hibernate get load 方法总结

      1.返回值:
      get()返回的是查询出来的实体对象,而load()查询出来的是一个目标实体的代理对象。

load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常;

get方法检索不到的话会返回null;

2.从检索执行机制上对比:

load方法的执行则比较复杂首先查找session的persistent Context(一级缓存)中是否有缓存,如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,查到记录返回(并且同时在二级缓存中存放查到的数据方便下次使用,若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。),查不到抛出异常。 若是lazy,则返回代理对象,而不到数据库中查找,除非使用此对象时,才到数据库中查找。

get方法先到一级缓存,然后二级,最后db查找。

hibernate – list和iterator方法的区别

1.获取方式不一样:

List的获取方式为:List list = query.list();

Iterator的获取方式:Iterator it = query.iterate();
2.执行sql不一样:

list()会直接查询数据库。

iterator()会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存中找,如果找不到,以id为条件再发一条sql到数据库,这样如果缓存中没有数据,则查询数据库的次数为n+1次。

3.list只查询一级缓存,而iterator会从二级缓存中查

4.list方法返回的对象都是实体对象,而iterator返回的是代理对象

5.session中list第二次发出,仍会到数据库査询

6.iterate 第二次,首先找session 级缓存

Hibernate的优/缺点:

优点:
1.更加对象化

以对象化的思维操作数据库,我们只需要操作对象就可以了,开发更加对象化。

2.移植性

因为Hibernate做了持久层的封装,你就不知道数据库,你写的所有的代码都具有可复用性。

3.Hibernate是一个没有侵入性的框架,没有侵入性的框架我们称为轻量级框架。

对比Struts的Action和ActionForm,都需要继承,离不开Struts。Hibernate不需要继承任何类,不需要实现任何接口。这样的对象叫POJO对象。

4.Hibernate代码测试方便。

5.提高效率,提高生产力。

缺点:

1.使用数据库特性的语句,将很难调优

2.对大批量数据更新存在问题

3.系统中存在大量的攻击查询功能

Hibernate openSession() 和 getCurrentSession的区别

方式说明

1.采用getCurrentSession()创建的Session会绑定到当前的线程中去、而采用OpenSession()则不会。

2.采用getCurrentSession()创建的Session在commit或rollback后会自动关闭,采用OpenSession()必须手动关闭。

3.采用getCurrentSession()需要在Hibernate.cfg.xml配置文件中加入如下配置:

如果是本地事物,及JDBC一个数据库:

1
<propety name=”Hibernate.current_session_context_class”>thread</propety>

如果是全局事物,及jta事物、多个数据库资源或事物资源:

1
<propety name=”Hibernate.current_session_context_class”>jta</propety>

总之:

getCurrentSession () 使用当前的session

openSession() 重新建立一个新的session

hibernate交给spring 管理的时,则首选getCurrentSession ()

Hibernate的缓存机制

一. 为什么要用Hibernate缓存:

​ Hibernate是一个ORM框架,会经常访问物理数据库。因此为了降低应用程序对数据库的访问频次,从而提高了应用程序的运行性能。

二. Hibernate缓存原理:

​ 1. Hibernate的一级缓存是Session的缓存,Session内置的缓存是不能被卸载的,Session的缓存是事务范围的缓存,即对应一个数据库事务或者一个应用事务的生命周期(例如买火车票这个动作,库存减一,买家加一,这就是一个事务),一级缓存中,持久化类的每个实例都具有唯一的OID,一级缓存存放的是数据库数据的拷贝。

​ 2. Hibernate的二级缓存是SessionFactory的缓存,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采取并发访问策略达到事务隔离。

​ 二级缓存是可选了,默认情况下二级缓存是不会启用的。二级缓存存放元数据和预定义的SQL,且是只读的。

​ 什么数据适合存放在二级缓存中呢?

​ 1)很少被修改的数据

​ 2)不太重要的数据,允许偶尔出现并发的数据

​ 3)不会被并发访问的数据

​ 4)常量数据

三. Hibernate缓存何时被清除:

​ 1. commit()方法被调用的时候。

​ 2. 执行查询时会清除缓存,从而保证查询结果能反映对象的最新状态。

​ 3. 显式调用session的flush()方法。

Hibernate中的一级缓存、二级缓存和懒加载

为什么使用缓存
  hibernate使用缓存减少对数据库的访问次数,从而提升hibernate的执行效率。hibernate中有两种类型的缓存:一级缓存和二级缓存。
一级缓存

  • Hibenate中一级缓存,也叫做session的缓存,当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session的缓存中。

    • 一级缓存可以在session范围内减少数据库的访问次数,只在session范围有效,session关闭,一级缓存失效。

    • session的缓存由hibernate维护, 用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。

特点

只在当前session范围有效,作用时间短,效果不是特别明显!

在短时间内多次操作数据库,效果比较明显!
二级缓存
Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。

Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架。

懒加载
当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
lazy 值

true     使用懒加载

false    关闭懒加载

extra   在集合数据懒加载时候提升效率,在真正使用数据的时候才向数据库发送查询的sql,如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!

hibernate 常见的主键策略有哪些

1.assigned
主键由外部程序负责生成,在 save() 之前必须指定一个。Hibernate不负责维护主键生成。与Hibernate和底层数据库都无关,可以跨数据库。在存储对象前,必须要使用主键的setter方法给主键赋值,至于这个值怎么生成,完全由自己决定,这种方法应该尽量避免

2.increment

由Hibernate从数据库中取出主键的最大值(每个session只取1次),以该值为基础,每次增量为1,在内存中生成主键,不依赖于底层的数据库,因此可以跨数据库。

3.sequence

采用数据库提供的sequence机制生成主键,需要数据库支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL这种不支持sequence的数据库

4.identity

identity由底层数据库生成标识符。identity是由数据库自己生成的,但这个主键必须设置为自增长,使用identity的前提条件是底层数据库支持自动增长字段类型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle这类没有自增字段的则不支持。

5.native

native由hibernate根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式,灵活性很强。如果能支持identity则使用identity,如果支持sequence则使用sequence。
6.uuid:
适用于char,varchar类型的作为主键.

谈谈Hibernate中inverse的作用

inverse属性默认是false,就是说关系的两端都来维护关系。
比如Student和Teacher是多对多关系,用一个中间表TeacherStudent维护。Gp)i
如果Student这边inverse=”true”, 那么关系由另一端Teacher维护,就是说当插入Student时,不会操作TeacherStudent表(中间表)。只有Teacher插入或删除时才会触发对中间表的操作。所以两边都inverse=”true”是不对的,会导致任何操作都不触发对中间表的影响;当两边都inverse=”false”或默认时,会导致在中间表中插入两次关系。

简述cascade属性的作用

1.all :对象所有操作进行级联操作
2.save-update : 执行保存和更改操作时进行级联操作
3.save 执行保存操作时进行级联操作。
4.delete : 执行删除操作时进行级联操作
5.none : 对所有操作不进行级联操作 默认。

什么是SessionFactory,她是线程安全么?

sessionFactory就是一个用于创建Hibernate的Session对象的工厂。SessionFactory通常是在应用启动时创建好的,应用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全的,所以多个线程可同时使用同一个SessionFactory。Java JEE应用一般只有一个SessionFactory,服务于客户请求的各线程都通过这个工厂来获得Hibernate的Session实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是 不可变的,一旦创建好后就不能对其进行修改了。

update()和saveOrUpdate()的区别

update()和saveOrUpdate()是用来对跨Session的PO(实体类)进行状态管理的。
update()方法操作的对象必须是持久化了的对象。也就是说,如果此对象在数据库中不存在的话,就不能使用update()方法。
saveOrUpdate()方法操作的对象既可以使持久化了的,也可以使没有持久化的对象。如果是持久化了的对象调用saveOrUpdate()则会 更新数据库中的对象;如果是未持久化的对象使用此方法,则save到数据库中。

hibernate拒绝连接、服务器崩溃的原因?最少写5个

  1. db没有打开

  2. 网络连接可能出了问题

  3. 连接配置错了

  4. 驱动的driver,url是否都写对了

  5. LIB下加入相应驱动,数据连接代码是否有误

  6. 数据库配置可能有问题

  7. 当前联接太多了,服务器都有访问人数限制的

  8. 服务器的相应端口没有开,即它不提供相应的服务

hibernate的三种状态之间如何转换

当对象由瞬时状态(Transient)一save()时,就变成了持久化状态。
当我们在Session里存储对象的时候,实际是在Session的Map里存了一份, 也就是它的缓存里放了一份,然后,又到数据库里存了一份,在缓存里这一份叫持久对象(Persistent)。
Session 一 Close()了,它的缓存也都关闭了,整个Session也就失效了, 这个时候,这个对象变成了游离状态(Detached),但数据库中还是存在的。
当游离状态(Detached)update()时,又变为了持久状态(Persistent)。 当持久状态(Persistent)delete()时,又变为了瞬时状态(Transient), 此时,数据库中没有与之对应的记录。

Hibernate 的OpenSessionView 问题

  1. 用于解决懒加载异常, 主要功能就是把 Hibernate Session 和一个请求的线程绑定在一起, 直到页面完整输出, 这样就可以保证页面读取数据的时候 Session 一直是开启的状态, 如果去获取延迟加载对象也不会报错。
  2. 问题: 如果在业务处理阶段大批量处理数据, 有可能导致一级缓存里的对象占用内存过多导致内存溢出, 另外一个是连接问题: Session 和数据库 Connection 是绑定在一起的, 如果业务处理缓慢也会导致数据库连接得不到及时的释放, 造成连接池连接不够. 所以在并发量较大的项目中不建议使用此种方式, 可以考虑使用迫切左外连接 (LEFT OUTER JOIN FETCH) 或手工对关联的对象进行初始化.
  3. 配置 Filter 的时候要放在 Struts2 过滤器的前面, 因为它要页面完全显示完后再退出

    hibernate jpa 注解

    1.@Entity(name=”EntityName”)
    必须,name为可选,对应数据库中一的个表

2.@Table(name=””,catalog=””,schema=””)
可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息
name:可选,表示表的名称。默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名
catalog:可选,表示Catalog名称,默认为Catalog(“”)。
schema:可选,表示Schema名称,默认为Schema(“”)。

3.@id
必须
@id定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键.置于getXxxx()前.

4.@GeneratedValue(strategy=GenerationType,generator=””)
可选
strategy:表示主键生成策略,有AUTO,INDENTITY,SEQUENCE 和 TABLE 4种,分别表示让ORM框架自动选择,
根据数据库的Identity字段生成,根据数据库表的Sequence字段生成,以有根据一个额外的表生成主键,默认为AUTO
generator:表示主键生成器的名称,这个属性通常和ORM框架相关,例如,Hibernate可以指定uuid等主键生成方式.
示例:

1
2
3
4
5
@Id
@GeneratedValues(strategy=StrategyType.SEQUENCE)
public int getPk() {
return pk;
}

5.@Basic(fetch=FetchType,optional=true)
可选
@Basic表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法,默认即为@Basic
fetch: 表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支抓取和延迟加载,默认为EAGER.
optional:表示该属性是否允许为null,默认为true
示例:

1
2
3
4
@Basic(optional=false)
public String getAddress() {
return address;
}

6.@Column
可选
@Column描述了数据库表中该字段的详细定义,这对于根据JPA注解生成数据库表结构的工具非常有作用.
name:表示数据库表中该字段的名称,默认情形属性名称一致
nullable:表示该字段是否允许为null,默认为true
unique:表示该字段是否是唯一标识,默认为false
length:表示该字段的大小,仅对String类型的字段有效
insertable:表示在ORM框架执行插入操作时,该字段是否应出现INSETRT语句中,默认为true
updateable:表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true.对于一经创建就不可以更改的字段,该属性非常有用,如对于birthday字段.
columnDefinition: 表示该字段在数据库中的实际类型.通常ORM框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是 DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的BLOB或 TEXT字段类型,该属性非常有用.
示例:

1
2
3
4
@Column(name="BIRTH", nullable="false", columnDefinition="DATE")
public String getBithday() {
return birthday;
}

7.@Transient
可选
@Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.
如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic
示例:

1
2
3
4
5
//根据birth计算出age属性
@Transient
public int getAge() {
return getYear(new Date()) – getYear(birth);
}

8.@ManyToOne(fetch=FetchType,cascade=CascadeType)
可选
@ManyToOne表示一个多对一的映射,该注解标注的属性通常是数据库表的外键
optional:是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true
fetch:表示抓取策略,默认为FetchType.EAGER
cascade:表示默认的级联操作策略,可以指定为ALL,PERSIST,MERGE,REFRESH和REMOVE中的若干组合,默认为无级联操作
targetEntity:表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity.
示例:

1
2
3
4
5
6
7
//订单Order和用户User是一个ManyToOne的关系
//在Order类中定义
@ManyToOne()
@JoinColumn(name=”USER”)
public User getUser() {
return user;
}

9.@JoinColumn
可选
@JoinColumn和@Column类似,介量描述的不是一个简单字段,而一一个关联字段,例如.描述一个@ManyToOne的字段.
name:该字段的名称.由于@JoinColumn描述的是一个关联字段,如ManyToOne,则默认的名称由其关联的实体决定.
例如,实体Order有一个user属性来关联实体User,则Order的user属性为一个外键,
其默认的名称为实体User的名称+下划线+实体User的主键名称
示例:
见@ManyToOne
@OneToMany(fetch=FetchType,cascade=CascadeType)
可选
10.@OneToMany描述一个一对多的关联,该属性应该为集体类型,在数据库中并没有实际字段.
fetch:表示抓取策略,默认为FetchType.LAZY,因为关联的多个对象通常不必从数据库预先读取到内存
cascade:表示级联操作策略,对于OneToMany类型的关联非常重要,通常该实体更新或删除时,其关联的实体也应当被更新或删除
例如:实体User和Order是OneToMany的关系,则实体User被删除时,其关联的实体Order也应该被全部删除
示例:

1
2
3
4
@OneTyMany(cascade=ALL)
public List getOrders() {
return orders;
}

Hibernate验证注解

注解 适用类型 说明 示例
@Pattern String 通过正则表达式来验证字符串 @Pattern(regex=”[a-z]{6}”)
@Length String 验证字符串的长度 @length(min=3,max=20)
@Email String 验证一个Email地址是否有效 @email
@Range Long 验证一个整型是否在有效的范围内 @Range(min=0,max=100)
@Min Long 验证一个整型必须不小于指定值 @Min(value=10)
@Max Long 验证一个整型必须不大于指定值 @Max(value=20)
@Size 集合或数组 集合或数组的大小是否在指定范围内 @Size(min=1,max=255)
-------------本文结束感谢您的阅读-------------
0%