Hibernate的一级缓存
缓存是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。
缓存中的数据是数据存储源中数据的拷贝。
Hlbernate的缓存分为一级缓存和二级缓存,Hibernate的这两级缓存都位于持久化层,存储的都是数据库数据的备份。其中第一级缓存为Hibernate的内置缓存,不能被卸载。
什么是Hibernate的一级缓存
Hlbernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的 java对象,在使用Hlbernate查询对象的时候,首先会使用对象属性的OID值在Hlbernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。
在Session接口的实现中包含一系列的Java集合,这些Java集合构成了Session缓存。只要 sesslon实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。固一级缓存也被称为是sesslon基本的缓存。
- Hlbernate的一级缓存有如下特点:
- 当应用程序调用session接口的save()、update()、saveOrUpdate时,如果session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
- 当调用session接口的load()、get()方法,以及Query接口的list()、Iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
- 当调用sesslon的close()方法时,session缓存会被清空。
- 测试一级缓存:
@Test
//证明Hibernate的一级缓存的存在
public void dame1(){
Session session=HibernateUtils.openSession();
Customer tx =session.get(Customer.class,1l);//马上发生一条sql语句查询1号客户,并将数据存入一级缓存
System.out.println(customer1);
Customer customer=session.get(Customer.class,1l);//没有发生sql语句从一级缓存中获取数据
System.out.println(customer2);
System.out.println(customer1==customer2);//true 一级缓存缓存的是对象的地址
tx.commit();
session.close();
}
一级缓存的内部结构:(快照区)
Hlbernate向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit() 方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。
Hibernate的事务控制
lbernate是对JDBC的轻量级封装,其主要功能是操作数据库。
- 什么是事务
在数据库操作中,一项事务(Transactlon)是由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元。当事务中的所有操作都正常完成时,整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被回滚。
其实事务总结起来理解为:逻辑上的一组操作,组成这组操作的各个单元,要么一起成功,要么一起失败。
- 事务的四个特性
- 原子性
- 表示将事务中所做的操作捆绑成一个不可分割的单元,即对事务所进行的数据修改等操作,要么全部执行,要么全都不执行。
- 一致性
- 表示事务完成时,必须使所有的数据都保持一致状态。
- 隔离性
- 指一个事务的执行不能被其它事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性
- 持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。提交后的其他操作或故障不会对其有任何影响。
- 原子性
事务的并发问题
在实际应用过程中,数据库是要被多个用户所共同访问的。在多个事务同时使用相同的数据时,可能会发生并发的问题,具体如下。
(1) 脏读:一个事务读取到另一个事务未提交的数据。
(2)不可重复读:一个事务读到了另一个事务己经提交的update的数据,导致在同一个事务中的多次查询结果不一致。
(3) 虚读/幻读:一个事务读到了另一个事务己经提交的Insert的数据,导致在同一个事务中的多次查询结果不一致。
Hibernate中的事务管理
其实有两种办法可以实现:
- 可以在业务侧获取到Session,并将Session作为参数传递给DAO.。
- 可以使用ThreadLoad将业务层的Session绑定到当前线程中,然后在Dao中获取Session的时候,都从当前线程中获取
Hibernate的其他API
- Query
Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session createQuery() 方法接受一个HQL语句,然后调用Query的list()或umqueResult()方法执行查询。所谓的HQL是
Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。
在Hibernate中使用Query对象的步骤,具体所示:
(1)获得Hibernate的Session对象。
(2) 编写HQL语句。
(3) 调用sessiomreateQuery创建查询对象。
(4) 如果HQL语句包含参数,则调用Query的setxxx设置参数。
(5)调用Query对象的hst()或uniqueResult()方法执行查询。
了解了使用Query对象的步骤后,接下来,通过具体示例来演示Query对象的查询操作。
Query执行HQL语句
/测试HQL语句
public class Demo {
@Test
//基本查询
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
// String hql = " from cn.itheima.domain.Customer ";
String hql = " from Customer "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
List<Customer> list = query.list(); // 返回list结果
//query.uniqueResult();//接收唯一的查询结果
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//条件查询
//HQL语句中,不可能出现任何数据库相关的信息的
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
String hql = " from Customer where cust_id = 1 "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//条件查询
//问号占位符
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
//query.setLong(0, 1l);
query.setParameter(0, 1l);
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//条件查询
//命名占位符
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
String hql = " from Customer where cust_id = :cust_id "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
query.setParameter("cust_id", 1l);
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//分页查询
public void fun5(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
String hql = " from Customer "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置分页信息 limit ?,?
query.setFirstResult(1);
query.setMaxResults(1);
//3> 根据查询对象获得查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
}
Query中除了使用hst()方法查询全部数据外,还有其它一些常用方法,具体如下:
- setter方法:Query接口中提供了一系列的setter方法用于设置查询语句中的参数,针对不同的数据类型,需要用到不同的setter方法。
- Iterator()方法:该方法用于查询语句,返回的结果是一个Iterator对象,在读取时只能按照顺序方式读取,它仅把使用到的数据转换成Java实体对象。
- uniqueResult()方法:该方法用于返回唯一的结果,在确保只有一条记录的查询时可以使用该方法。
- executeUpdate()方法:该方法是Hibernate3的新特性,它支持HQL语句的更新和删除操作。 setFirstResult()方法:该方法可以设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。
- setMaxResult()方法:该方法用于设置结果集的最大记录数,通常与setFirstResult()方法结合使用,用于限制结果集的范围,以实现分页功能。
- Criteria
Cnteria是一个完全面向对象,可扩展的条件查询AP,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写,它是Hibernate框架的核心查询对象。Criteria查询,又称为QBC 查询(Query By Critena),它是Hibernate的另一种对象检索方式。
通常,使用对象查询数据的主要步骤,具体如下:
(1)获得Hibernate的Session对象。
(2) 通过Session获得Critena对象。
(3) 使用Restrictions的静态方法创建Critenon条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回Critenon实例,每个实例代表一个查询条件。
(4) 向critena对象中添加Criterion查询条件。criteria的add()方法用于加入查询条件。
(5) 执行Critenta的list()或umqueResult()获得结果。
//测试Criteria查询
public class Demo {
@Test
//基本查询
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
System.out.println(list);
// Customer c = (Customer) criteria.uniqueResult();
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//条件查询
//HQL语句中,不可能出现任何数据库相关的信息的
// > gt
// >= ge
// < lt
// <= le
// == eq
// != ne
// in in
// between and between
// like like
// is not null isNotNull
// is null isNull
// or or
// and and
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//添加查询参数 => 查询cust_id为1的Customer对象
criteria.add(Restrictions.eq("cust_id", 1l));
//执行查询获得结果
Customer c = (Customer) criteria.uniqueResult();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//分页查询
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置分页信息 limit ?,?
criteria.setFirstResult(1);
criteria.setMaxResults(2);
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//查询总记录数
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询的聚合函数 => 总行数
criteria.setProjection(Projections.rowCount());
//执行查询
Long count = (Long) criteria.uniqueResult();
System.out.println(count);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
}
- SQLQuery
SQLQuery这个就比较简单了,这个接口用于一个接收sql语句进行查询,然后调用list()或者uniqueResult()方法进行查询,但是sql语句不会封装到实体中,需要我们手动写代码以封装到实体中
//测试原生SQL查询
public class Demo {
@Test
//基本查询
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1 书写sql语句
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//3 调用方法查询结果
List<Object[]> list = query.list();
//query.uniqueResult();
for(Object[] objs : list){
System.out.println(Arrays.toString(objs));
}
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//基本查询
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1 书写sql语句
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//条件查询
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1 书写sql语句
String sql = "select * from cst_customer where cust_id = ? ";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, 1l);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
@Test
//分页查询
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1 书写sql语句
String sql = "select * from cst_customer limit ?,? ";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, 0);
query.setParameter(1, 1);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
}