实体类对象的状态(概念)
实体类状态有三种:
瞬时态:
对象里面没有id值,对象与session没有关联。
//瞬时态一般是做添加操作。
//对象与session没有关系是因为.save();里面可以传任何的对象进去,和Book类没有直接的联系。
Book book=new Book("逻辑思维训练",36);
session.save(book);
持久态:
对象里面有id值,对象与session有关联。
//对象有id值,并且通过session查询了出来。
Book book=session.get(Book.class,1);
//而session有关系是因为,session直接的返回值为Book类型。Book类型和session通过泛型起到了绑定的关系。
托管态:
对象有id值,对象与session没有关联。
Book book=new Book(3,"大话数据结构",65);
session.delete(book);
Hibernate的一级缓存
什么是缓存:
数据存到数据库里面,数据库本身是文件系统,使用流的方式操作文件,效率不是很高。
- 把数据存到内存里面,不需要使用流的方式,可以直接读取内存中的数据。
- 把数据放到内存中,提高读取效率。
Hibernate缓存
Hibernate框架中提供了很多的优化方式,hibernate的缓存就是一种优化方式
hibernate缓存特点
第一类:hibernate的一级缓存:
- hibernate的一级缓存默认是打开的。
- hibernate的一级缓存使用范围是session的范围,从session创建到session关闭的范围。
- hibernate的一级缓存中,存储数据必须 为持久态数据。(也就是有id,并且依赖session)
第二类:hibernate的二级缓存
- 目前已经不使用了,替代技术 redis。
- 二级缓存默认不是打开的,需要配置。
- 二级缓存使用范围,是sessionFactory范围。
验证一级缓存的存在:
//java代码
public static void showCatch(){
SessionFactory sessionFactory=HibernateUtils.getSessionFactory();
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
Book book1=session.get(Book.class, 1);
System.out.println(book1);
Book book2=session.get(Book.class, 1);
System.out.println(book2);
transaction.commit();
session.close();
}
//输出结果
Hibernate:
select
book0_.id as id1_0_0_,
book0_.bookname as bookname2_0_0_,
book0_.price as price3_0_0_
from
book book0_
where
book0_.id=?
Book [bookname=精进:如何成为一个厉害的人, price=50, id=1]
Book [bookname=精进:如何成为一个厉害的人, price=50, id=1] //在这里可以看到,并没有发送sql语句,而是直接就查询输出了,很明显这是查询的一级
缓存中的内容。
一级缓存的执行过程:
Book book1=session.get(Book.class, 1);
//在第一次通过session.get(Object);方法获取数据的时候,Hibernate会通过实体类的类型和id(主键)在一级缓存中查找是否缓存中有数据,没有查找到才
会到数据库里面去找。在hibernate获取到数据之后会把数据放到一级缓存中去,该数据是一个对象。记住是一个对象,很多开发者认为是存的数据,其实是存
的对象,也就是该对象的引用。等下我会证明!!
Book book2=session.get(Book.class,1);
//所以这次你才会看到并没有输出底层的数据库sql语句。
//因为Hibernate直接从自己的一级缓存中读取到数据了。读取方式是判断当前类型是否和一级缓存中的类型相同,如果相同再判断id是否相同,都相同就把该
对象的引用返回给我们。
上面说Hibernate中存储的是对象的引用,下面我来证明!!
public static void showCatch(){
SessionFactory sessionFactory=HibernateUtils.getSessionFactory();
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
Book book1=session.get(Book.class, 1);
System.out.println(book1);
book1.setPrice(30);
Book book2=session.get(Book.class, 1);
System.out.println(book2);
System.out.println(book1==book2);
transaction.commit();
session.close();
}
//输出结果
Hibernate:
select
book0_.id as id1_0_0_,
book0_.bookname as bookname2_0_0_,
book0_.price as price3_0_0_
from
book book0_
where
book0_.id=?
Book [bookname=精进:如何成为一个厉害的人, price=50, id=1]
Book [bookname=精进:如何成为一个厉害的人, price=30, id=1]
true//看到没有!!!这里为true。这是关键!!!
Hibernate:
update
book
set
bookname=?,
price=?
where
id=?
//可以看到,我们在上面java代码中把price的值从50修改为30后,当我们再次执行session.get(Object)获取目标对象,可以看到输出来的值是30。当我们让
两个对象比较引用的时候,返回结果是true。所以这就很明显了。Hibernate一级缓存中存储的是对象的引用。最后当我们通过transaction.commit()方法提交
事务后,Hibernate还会通过某种方法判断一级缓存中的数据是否被修改,如果修改后还会作更新数据库的操作。自动更新数据库的操作是Hibernate的一个特
性。这个特性只针对 持久态 有效。
再来看看下面的代码:
public static void showCatch(){
SessionFactory sessionFactory=HibernateUtils.getSessionFactory();
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
Book book1=session.get(Book.class, 1);
System.out.println(book1);
book1.setPrice(50);
transaction.commit();
session.close();
}
//输出结果
Hibernate:
select
book0_.id as id1_0_0_,
book0_.bookname as bookname2_0_0_,
book0_.price as price3_0_0_
from
book book0_
where
book0_.id=?
Book [bookname=精进:如何成为一个厉害的人, price=30, id=1]
Hibernate:
update
book
set
bookname=?,
price=?
where
id=?
//很明显可以看到,再重新设置数据后就会更新数据库。
上面我们说了Hibernate还会通过某种方法判断一级缓存中的数据是否被修改,如果修改后还会作更新数据库的操作。
这个过程是Hibernate一级缓存的特性。
它有两个作用:
- 因为Session的生命期往往很短,存在于Session内部的最快缓存的生命期当然也很短,所以第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。
- 其主要作用是保持Session内部数据状态同步。
上面说到判断一级缓存中的数据是否被修改的方法是:
- 当我们修改user对象里面的值,就会修改到一级缓存中的实体对象的值。
- 其实在我们没有修改值之前,也就是刚查询出来之后,该实体对象会在一级缓存相对应的快照区保存一个快照。
- 快照大家都懂,就是把实体对象的值复制拷贝一份出来。形成一个新的实体对象。
- 当我们执行方法transaction.commit()时,里面就会比较快照区和一级缓存中的数据是否一致,如果不一致就会拿一级缓存中的数据去更新数据库中的数据。
- 注意这里的一级缓存是存储的我们第一次查询出来的实体对象引用。
- 判断是否一级缓存中存储的为我们查询出来的实体对象引用,关键就是我们通过判断两次在一个session中获取的结果对象引用是相同的。也就是我们上面输出true。
- 最后,我们用session.get(Object);获取值的路径是从一级缓存中读取的。