实体类状态有三种:
瞬时态:
对象里面没有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的一级缓存使用范围是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);获取值的路径是从一级缓存中读取的。