Hibernate笔记(核心组件、运行过程、缓存机制、对象状态转换)

参考:https://juejin.im/post/6844903573004746766

一、Hibernate核心组件

除配置文件,映射文件和持久化类外,Hibernate的核心组件包括以下几部分:

1.Configuration类:用来读取Hibernate配置文件,并生成SessionFactory对象。一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。

2.SessionFactory接口:产生Session实例工厂。

3.Session接口:用来操作PO。它有get(),load(),save(),update()和delete()等方法用来对PO进行加载,保存,更新及删除等操作。它是Hibernate的核心接口。

4.Query接口:用来对PO进行查询操。它可以从Session的createQuery()方法生成。

5.Transaction接口:用来管理Hibernate事务,它主要方法有commit()和rollback(),可以从Session的beginTrancation()方法生成。

二、Hibernate运行过程

1、通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件

2、由hibernate.cfg.xml中的<mappingresource="com/xx/User.hbm.xml"/>读取解析映射信息。

3、通过config.buildSessionFactory();//得到sessionFactory。

4、sessionFactory.openSession();//得到session。

用户自行提供JDBC连接。
  Connection con=dataSource.getConnection();
  Session s=sessionFactory.openSession(con);

让SessionFactory提供连接
  Session s=sessionFactory.openSession();

5、session.beginTransaction();//开启事务。

6、persistent operate;持久化操作

可通过Session对象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法对PO进行加载,保存,更新,删除等操作;在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象执行查询操作

7、session.getTransaction().commit();//提交事务

8、关闭session;

9、关闭sessionFactory;

三、Hibernate中对象的三种状态及相互转化

1、临时状态

临时状态对象特征:

①、使用 new 创建出来的对象,没有设置OID

②、没有被 session 托管,换句话说 对象数据 存放在内存中, 没有存放到 session 缓存中

③、临时对象数据 与 数据库中的数据 还没任何关联

2、持久状态

持久状态对象特征:

①、要么是从数据库中使用 get 或 load 方法查询到的数据对象, 要么是 使用save 或 update 方法数据转变成持久层对象

②、对象数据被 session 托管,有OID。换句话说 对象数据 在 session 缓存中有一份,在数据库中有相应的记录

③、持久化对象有自动更新数据库的能力,当持久化对象的属性被改变时,调用Transaction的commit方法后,会对数据库执行update SQL操作。注意,不能改变主键的值,否则会报错。

3、游离状态

游离状态对象特征:

①、主要是通过 持久状态对象,调用 session.evict() 或 session.clear() 或 session.close() 得到的,也可以new 一个设置 id 值的对象。

②、session 缓存中没有,内存中有的对象(注: 该对象设置了 oid 值)

③、游离状态的数据,可以使用update() 或者 saveOrUpdate() 或者 lock() 方法,将数据从 "游离状态" 转换为 "持久化"

4、转换

 

5、三种状态的区别

*是否在Session对象管理下,如果在,则一定是持久态,否则是临时太或者游离态。

*是否持有OID,没有OID的是临时状态,有OID的是持久化状态或者游离状态。

 

临时状态

(Transient)

持久化状态

(Persistent)

游离状态

(Detached)

是否处于Session缓存中

×

×

数据库中是否有对应记录

×

 是否有OID

× 

 √

 √

四、Hibernate一级缓存

一级缓存  ——自带的,不可卸载.

Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效!

只要是持久化对象状态的,都受Session管理,也就是说,都会在Session缓存中!

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

        Hibernate采用快照模式。当数据对象被查询出来之后,不仅在一级缓存中存有一份数据,在快照中也存了一份。当对象被改变时,只改变缓存区中的数据内容,不该表快照区的数据。提交事务(执行Transaction.commit()),首先对比缓存区和快照区的内容,如果一致,则不做任何操作;如果不一致,则把缓存区中的数据更新到数据库,并把缓存区的数据也更新到快照区,形成新的快照。在对比的同时,完成对OID的验证一致性验证。

注意:只有数据变成了持久态之后,数据才有快照区副本。

 缓存相关的方法

和缓存有关常用的方法有三个:

  • session.flush(); 让一级缓存与数据库同步

  • session.evict(arg0); 清空一级缓存中指定的对象

  • session.clear(); 清空一级缓存中缓存的所有对象

 一般地,我们在批处理的时候会用,因为缓存也是有大小的,如果1000条数据插入进去都要缓存,那么Hibernate可能就崩了...

  • 每隔一定记录数,先与数据库同步 flush()
  • 再清空缓存 clear()

Iterator与list区别

我们使用HQL查询全部数据的时候,可以使用list()得到所有的数据,也可以使用iterator()得到一个迭代器,再遍历迭代器...那它们有什么区别呢?

五、懒加载

懒加载就是当使用数据的时候才去获取数据、执行对应的SQL语句...当还没用到数据的时候,就不加载对应的数据!

主要目的就是为了提高Hibernate的性能,提高执行效率

  • get: 及时加载,只要调用get方法立刻向数据库查询
  • load:默认使用懒加载,当用到数据的时候才向数据库查询。

我们可以在对应的配置文件用通常lazy属性来设置

<class name="IdCard" table="IdCard" lazy="false">

 lazy有三个属性:

  • true 使用懒加载
  • false 关闭懒加载
  • extra (在集合数据懒加载时候提升效率)【只有在set、list等集合标签中使用】
    • 在真正使用数据的时候才向数据库发送查询的sql;
    • 如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!

懒加载异常

当Session关闭后,就不能使用懒加载了,否则会报出异常

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session

报出了这个异常,我们有4种方法解决:

  • 方式1: 先使用一下数据
    • dept.getDeptName();
  • 方式2:强迫代理对象初始化
    • Hibernate.initialize(dept);
  • 方式3:关闭懒加载
    • 设置lazy=false;
  • **方式4: 在使用数据之后,再关闭session! **

 六、Hibernate二级缓存

默认情况下没有打开。

前面我们已经讲解过了一级缓存,一级缓存也就是Session缓存,只在Session的范围内有效...作用时间就在Session的作用域中,范围比较小

Hibernate为我们提供了二级缓存功能:二级缓存是基于应用程序的缓存,所有的Session都可以使用

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

Hibernate二级缓存:存储的是常用的类

配置二级缓存

既然二级缓存是Hibernate自带的,那么我们可以在hibernate.properties文件中找到对应的信息..

  • #hibernate.cache.use_second_level_cache false【二级缓存默认不开启,需要手动开启】
  • #hibernate.cache.use_query_cache true 【开启查询缓存】

choose a cache implementation 【二级缓存框架的实现】

  • #hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
  • #hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
  • hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 默认实现
  • #hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
  • #hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
  • #hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

通过配置文件我们可以发现,二级缓存默认是不开启的,需要我们手动开启,以下步骤:

  • 1)开启二级缓存
  • 2)指定缓存框架
  • 3)指定哪些类加入二级缓存

开启二级缓存

在hibernate.cfg.xml文件中开启二级缓存

<!-- a. 开启二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property>

指定缓存框架

指定Hibernate自带的二级缓存框架就好了

<!-- b. 指定使用哪一个缓存框架(默认提供的) --> <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

指定哪些类加入二级缓存

<!-- c. 指定哪一些类,需要加入二级缓存 --> <class-cache usage="read-write" class="zhongfucheng.aa.Monkey"/> <class-cache usage="read-only" class="zhongfucheng.aa.Cat"/>

缓存策略

usage的属性有4种:

  • ** 放入二级缓存的对象,只读; **
  • 非严格的读写
  • 读写; 放入二级缓存的对象可以读、写;
  • (基于事务的策略)

查询缓存

list()和iterator()会把数据放在一级缓存,但一级缓存只在Session的作用域中有效...如果想要跨Session来使用,就要设置查询缓存

我们在配置文件中还看到了查询缓存这么一条配置..

	#hibernate.cache.use_query_cache true      【开启查询缓存】

 也就是说,默认的查询数据是不放在二级缓存中的,如果我们想要把查询出来的数据放到二级缓存,就需要在配置文件中开启

<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>

 在使用程序查询的时候,也要调用setCacheable()方法,设置为查询缓存。


	@Test
	public void listCache() {
		Session session1 = sf.openSession();
		session1.beginTransaction();
		// HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】
		Query q = session1.createQuery("from Dept").setCacheable(true);
		System.out.println(q.list());
		session1.getTransaction().commit();
		session1.close();
		
		
		Session session2 = sf.openSession();
		session2.beginTransaction();
		q = session2.createQuery("from Dept").setCacheable(true);
		System.out.println(q.list());  // 不查询数据库: 需要开启查询缓存
		session2.getTransaction().commit();
		session2.close();
	}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值