在之前的文章【ORM规范】初探JPA与Hibernate 中我们初步了解了Hibernate,ORM以及JPA的概念和初步理解。
Hibernate并不难,无非是对JDBC进一步封装。这里希望深层次的理解和解析Hibernate。
Hibernate的流程
这里在上一篇文章中写过,这里复习一下
从上图中,我们可以看出Hibernate六大核心接口,两个主要配置文件,以及他们直接的关系。Hibernate的所有内容都在这了。那我们根据这张图认识一下整个流程。
-
1、Configuration接口:通过Configuration().configure()读取并解析hibernate.cfg.xml配置文件,并启动Hibernate
由hibernate.cfg.xml中的< mapping resource=”com/xx/User.hbm.xml”/>读取并解析映射信息 -
2、SessionFactory接口:负责初始化Hibernate(通过config.buildSessionFactory(); //创建SessionFactory)
-
3、Session接口:负责持久化对象的CRUD操作(sessionFactory.openSession(); //打开Sesssion)
-
4、Transaction接口:负责事务(session.beginTransaction(); //创建事务Transation,session.getTransaction().commit(); //提交事务)
-
5、Query接口和Criteria接口:负责执行各种数据库查询(持久化操作)
最后需要:关闭Session,关闭SesstionFactory
注意:Configuration实例是一个启动期间的对象,一旦SessionFactory创建完成它就被丢弃了。
如果对hibernate运行都不熟悉的朋友,可以直接看这篇简易教程 史上最简单的Hibernate入门简介
hibernate 缓存机制
关于缓存
什么是缓存?
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
缓存有什么好处?
缓存的好处是降低了数据库的访问次数,提高应用性能,减少了读写数据的时间
什么时候适合用缓存?
程序中经常用到一些不变的数据内容,从数据库查出来以后不会去经常修改它而又经常要用到的就可以考虑做一个缓存,以后读取就从缓存来读取,而不必每次都去查询数据库。因为硬盘的速度比内存的速度慢的多。从而提高了程序的性能,缓存的出现就会为了解决这个问题
hibernate中的缓存
hibernate的缓存机制,包括一级缓存(session级别)、二级缓存(sessionFactory级别)以及查询缓存。
在深入了解缓存机制前,必须了解hibernate对象的状态:
hibernate对象的状态
分为四个状态:临时状态,持久化状态,游离状态,删除状态
对象的状态转换:
一级缓存(session级别)
session = HibernateUtil.openSession();
session.beginTransaction();
User user = new User();
user.setUsername("aaa");
user.setPassword("aaa");
user.setBorn(new Date());
//以上u就是Transient(瞬时状态),表示没有被session管理并且数据库中没有
//执行save之后,被session所管理,而且,数据库中已经存在,此时就是Persistent状态
session.save(user);
//此时u是持久化状态,已经被session所管理,当在提交时,会把session中的对象和目前的对象进行比较
//如果两个对象中的值不一致就会继续发出相应的sql语句
user.setPassword("bbb");
//此时会发出2条sql,一条用户做插入,一条用来做更新
session.getTransaction().commit();
在调用了save方法后,此时user已经是持久化对象了,被保存在了session一级缓存当中,这时user又重新修改了属性值,那么在提交事务时,此时hibernate对象就会拿当前这个user对象和保存在session缓存中的user对象进行比较,如果两个对象相同,则不会发送update语句,否则,如果两个对象不同,则会发出update语句。
Hibernate: insert into t_user (born, password, username) values (?, ?, ?)
Hibernate: update t_user set born=?, password=?, username=? where id=?
再来看看下面的代码:
session = HibernateUtil.openSession();
session.beginTransaction();
User u = new User();
u.setBorn(new Date());
u.setUsername("zhangsan");
u.setPassword("zhangsan");
session.save(u);
u.setPassword("222");
session.save(u);//该条语句没有意义
u.setPassword("zhangsan111");
session.update(u);//该条语句没有意义
u.setBorn(sdf.parse("1988-12-22"));
session.update(u);//该条语句没有意义
session.getTransaction().commit();
这个时候会发出多少sql语句呢?还是同样的道理,在调用save方法后,u此时已经是持久化对象了,记住一点:如果一个对象以及是持久化状态了,那么此时对该对象进行各种修改,或者调用多次update、save方法时,hibernate都不会发送sql语句,只有当事务提交的时候,此时hibernate才会拿当前这个对象与之前保存在session中的持久化对象进行比较,如果不相同就发送一条update的sql语句,否则就不会发送update语句
二级缓存(sessionFactory级别)
在上面,如果session关闭或者清除缓存以后(通过session.clear();//清除所有缓存,session.evict();//清除指定缓存),一级缓存就不存在了,所以如果再查询的时候,就会再发sql。要解决这种问题,我们应该怎么做呢?这就要我们来配置hibernate的二级缓存了,也就是sessionFactory级别的缓存。
分为下面几个步骤:
- 1.hibernate并没有提供相应的二级缓存的组件,所以需要加入额外的二级缓存包,常用的二级缓存包是EHcache。
- 2.在hibernate.cfg.xml配置文件中配置我们二级缓存的一些属性
- 3.配置hibernate的二级缓存是通过使用 ehcache的缓存包,所以我们需要创建一个 ehcache.xml 的配置文件,来配置我们的缓存信息,将其放到项目根目录下
- 4.开启我们的二级缓存
具体参考文章hibernate缓存机制详细分析
在配置了二级缓存以后,当我们session关闭以后,我们再去查询对象的时候,此时hibernate首先会去二级缓存中查询是否有该对象,有就不会再发sql了。
二级缓存缓存的仅仅是对象,如果查询出来的是对象的一些属性,则不会被加到缓存中去
二级缓存不会缓存我们的hql查询语句,要想解决这个问题,我们就要配置我们的查询缓存了。
查询缓存(sessionFactory级别)
我们如果要配置查询缓存,只需要在hibernate.cfg.xml中加入一条配置即可:
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
然后我们如果在查询hql语句时要使用查询缓存,就需要在查询语句后面设置这样一个方法:
List<Student> ls = session.createQuery("from Student where name like ?")
.setCacheable(true) //开启查询缓存,查询缓存也是SessionFactory级别的缓存
.setParameter(0, "%王%")
.setFirstResult(0).setMaxResults(50).list();
如果是在annotation中,我们还需要在这个类上加上这样一个注解:@Cacheable
查询缓存也是sessionFactory级别的缓存
只有当 HQL 查询语句完全相同时,连参数设置都要相同,此时查询缓存才有效
在一级缓存,二级缓存和查询缓存都打开的情况下作查询操作时这样的:查询普通属性,会先到查询缓存中取,如果没有,则查询数据库;查询实体,会先到查询缓存中取id,如果有,则根据id到缓存(一级/二级)中取实体,如果缓存中取不到实体,再查询数据库。
hibernate的检索策略
参考文章:https://blog.csdn.net/weixin_39592397/article/details/80857737
网友评论