Hibernate的一级缓存&事务管理及其配置
持久态对象:
自动更新数据库,原理是一级缓存。
缓存:是一种优化的方式,将数据存入内存,从缓存/内存中获取,不用通过存储源
Hibernate框架中提供了优化手段:缓存,抓取策略
Hibernate中提供了两种缓存机制:一级缓存,二级缓存
一级缓存:session级缓存,一级缓存生命周期与session一致(是由session中一系列Java集合构成)
二级缓存:SessionFactory级别的缓存,需要配置的缓存,开发中一般用Redis替代了。
一级缓存:
即session缓存,session缓存是一块内存空间,存放相互管理的Java对象。
在使用Hibernate查询对象的时候,首先使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到,直接在一级缓存中取出来使用,不再查询数据库。
如果没有找到相同OID值对象,则回去数据库中查询。当从数据库中查询所需数据时,该数据也会放到一级缓存中。
在Session接口的实现中包含一系列的Java集合,这些Java集合构成了Session缓存。只要Session缓存没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。
特点:
- 当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中国去。
- 当调用load()、get()时,或者Query接口中的list()、iterator时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询的对象,再去数据库中查询对应对象,并添加到一级缓存。
- 当调用close()时,session缓存会被清空。
作用:减少对数据库访问的次数。
证明一级缓存的存在:
一级缓存的快照区:
package com.Hidemo1; import java.io.Serializable; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.HiUtils.HibernateUtils; public class HibernateDemo3 { @Test /** * 一级缓存的测试 */ public void demo1(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); // 证明以及缓存的存在 /* Customer customer = session.get(Customer.class, 3l); System.out.println(customer); Customer customer2 = session.get(Customer.class, 3l); System.out.println(customer2); System.out.println(customer == customer2); */ Customer customer3 = new Customer(); customer3.setCust_name("凤姐"); Serializable id = session.save(customer3); Customer customer4 = session.get(Customer.class, id); System.out.println(customer4); transaction.commit(); session.close(); } @Test /** * 一级缓存的快照区 */ public void demo2(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = session.get(Customer.class, 5l);//发送sql语句查询,同时放入到一级缓存中 customer.setCust_name("凤姐"); transaction.commit(); session.close(); } @Test /** * 一级缓存的快照区 */ public void demo3(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = session.get(Customer.class, 5l);//发送sql语句查询,同时放入到一级缓存中 session.clear();//清空所有 // session.evict(customer);//清除单个 Customer customer2 = session.get(Customer.class, 5l);//发送第二次sql语句 transaction.commit(); session.close(); } }
回顾事务:
什么是事务:指的是逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功,要么全部失败。
事务的特性:
- 原子性:事务不可分割
- 一致性:事务执行的前后完整性保持一致
- 隔离性 : 事务在执行过程中不应该受到其他事务的干扰。
- 持久性 : 代表一个事务完成后数据持久到数据库
如果不考虑隔离性,引发安全问题
读问题
- 脏读 : 一个事务读到另一个事务未提交的事务
- 不可重复读 : 一个事务读到另一个已经提交的update数据,导致前后查询结果不一致。
- 虚读 : 一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结构不一致
写问题(了解)
- 引发丢失更新
读问题的解决:
设置事务的隔离级别:
- Read Uncommitted : 以上的读问题都会发生
- Read Committed : 解决脏读,但是不可重复读和虚读有可能发生 Oracle
- Repeatable read : 解决脏读和不可重复读,但是虚读有可能发生 MySQL
- Serializable : 解决所有读问题
Hibernate中设置事务隔离级别:
- Read Uncommitted :1
- Read Committed : 2
- Repeatable read : 4
- Serializable : 8
在核心配置文件中加上:<property name="hibernate.connection.isolation">4</property>
Service层事务:
事务应该加在业务层,dao只是封装单个操作。例如转账,可能要经过多个操作,所以事务应该封装在业务层。
ThreadLocal:绑定线程的对象。在业务上加事务,就必须绑定ThreadLocal
- 将连接绑定到当前线程中。
- 在DAO方法中,通过当前的线程获得到连接对象。
- Hibernate框架内部绑定好了ThreadLocal
- 在SessionFactory中,提供了一个方法,getCurrentSession,获取当前线程中的Session,默认不能用,需要通过配置。
Hibernate解决Service的事务管理:
改写工具类:
添加配置:
getCurrentSession无需close,线程结束自动关闭Session