Hibernate中对象的状态:
学习Hibernate的对象状态是为了更清晰地知道Hibernate的设计思想,以及是一级缓存的基础...当然啦,也就一点点知识
当我们直接new出来的对象就是临时/瞬时状态的..
当保存在数据库中的对象就是持久化状态了
我们来测试一下:当对对象属性进行更改的时候,会反映到数据库中!
session.save(idCard); idCard.setIdCardName("我是测试持久化对象");
当Session关闭了以后,持久化的对象就变成了游离状态了...
Hibernate有一级缓存和二级缓存之分,这里主要讲解一级缓存
Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效!
只要是持久化对象状态的,都受Session管理,也就是说,都会在Session缓存中!
Session的缓存由hibernate维护,用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。
减少对数据库的访问次数!从而提升hibernate的执行效率!
我们来看一下Hibernate是怎么减少对数据库访问的次数的。
现在我的User表有这么一条记录:
//把数据放进cache User user = (User) session.get(User.class, 1); //发现要修改的字段和cache一样,不执行 user.setUserName("你好2");
取数据也是一样的
User user = null; user = (User) session.get(User.class, 1); user = (User) session.get(User.class, 1);
和缓存有关常用的方法有三个:
session.clear(); 清空一级缓存中缓存的所有对象
clear
User user = null; user = (User) session.get(User.class, 1); //清除缓存,那么下面获取的时候,就不能从缓存里面拿了 session.clear(); user = (User) session.get(User.class, 1);
在有缓存的情况下,修改同一条记录的数据,以最后的为准...因此只有一条update
User user = null; user = (User) session.get(User.class, 1); user.setUserName("我是第一"); user = (User) session.get(User.class, 1); user.setUserName("我是第二");
我让强制让它和数据库同步的话,就有两条update了
User user = null; user = (User) session.get(User.class, 1); user.setUserName("我是第一"); session.flush(); user = (User) session.get(User.class, 1); user.setUserName("我是第二");
一般地,我们在批处理的时候会用,因为缓存也是有大小的,如果1000条数据插入进去都要缓存,那么Hibernate可能就崩了...
值得注意的是:不同的Session是不会共享缓存的!
我们使用HQL查询全部数据的时候,可以使用list()得到所有的数据,也可以使用iterator()得到一个迭代器,再遍历迭代器...那它们有什么区别呢?
。。。。当时看视频的时候说是下图:
但是我在测试的时候:List也可以获取缓存的数据
当然啦,Iterator也是可以获取缓存的数据
因此,在获取数据的时候还是使用list()方便!
懒加载就是当使用数据的时候才去获取数据、执行对应的SQL语句...当还没用到数据的时候,就不加载对应的数据!
主要目的就是为了提高Hibernate的性能,提高执行效率!
User user = (User) session.load(User.class, 1); System.out.println("________"); System.out.println(user);
我们可以在对应的配置文件用通常lazy属性来设置
关闭懒加载:
<class name="IdCard" table="IdCard" lazy="false">
lazy有三个属性:
当Session关闭后,就不能使用懒加载了,否则会报出异常
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
报出了这个异常,我们有4种方法解决:
前面我们已经讲解过了一级缓存,一级缓存也就是Session缓存,只在Session的范围内有效...作用时间就在Session的作用域中,范围比较小
Hibernate为我们提供了二级缓存功能:二级缓存是基于应用程序的缓存,所有的Session都可以使用
Hibernate二级缓存:存储的是常用的类
既然二级缓存是Hibernate自带的,那么我们可以在hibernate.properties文件中找到对应的信息..
通过配置文件我们可以发现,二级缓存默认是不开启的,需要我们手动开启,以下步骤:
在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"/>
测试:
我们知道一级缓存是Session的缓存,那么我们在测试二级缓存的时候使用两个Session来测试就好了。如果第二个Session拿到的是缓存数据,那么就证明二级缓存是有用的。
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //获取加载配置管理类 Configuration configuration = new Configuration(); //加载类对应的映射文件! configuration.configure().addClass(Animal.class); //创建Session工厂对象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象 Session session1 = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象 Transaction transaction = session1.getTransaction(); //开启事务 transaction.begin(); Monkey monkey = (Monkey) session1.get(Monkey.class,"40283f815be67f42015be67f43240001" ); System.out.println(monkey.getName()); System.out.println("-----------------------"); Session session2 = factory.openSession(); Transaction transaction2 = session2.getTransaction(); transaction2.begin(); Monkey monkey2 = (Monkey) session1.get(Monkey.class, "40283f815be67f42015be67f43240001"); System.out.println(monkey2.getName()); //提交事务 transaction.commit(); transaction2.commit(); //关闭Session session1.close(); session2.close(); } }
得到的是缓存数据!
我们在把Animal类放进二级缓存的时候,用法为只读
也就是说,只能读取,不能写入,我们来看看写入会怎么样:
monkey2.setName("小猴子");
抛出了异常....
usage的属性有4种:
<class-cache usage="read-only"/>
放入二级缓存的对象,只读; <class-cache usage="nonstrict-read-write"/>
非严格的读写<class-cache usage="read-write"/>
读写; 放入二级缓存的对象可以读、写;<class-cache usage="transactional"/>
(基于事务的策略)如果我们在数据库查询的数据是集合...Hibernate默认是没有为集合数据设置二级缓存的...因此还是需要去读写数据库的信息
接下来,我们就看看把集合设置为二级缓存是什么做的:
<!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] --> <collection-cache usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>
public void testCache() { Session session1 = sf.openSession(); session1.beginTransaction(); // a. 查询一次 Dept dept = (Dept) session1.get(Dept.class, 10); dept.getEmps().size();// 集合 session1.getTransaction().commit(); session1.close(); System.out.println("------"); // 第二个session Session session2 = sf.openSession(); session2.beginTransaction(); // a. 查询一次 dept = (Dept) session2.get(Dept.class, 10); // 二级缓存配置好; 这里不查询数据库 dept.getEmps().size(); session2.getTransaction().commit(); session2.close(); }
list()和iterator()会把数据放在一级缓存,但一级缓存只在Session的作用域中有效...如果想要跨Session来使用,就要设置查询缓存
我们在配置文件中还看到了查询缓存这么一条配置..
#hibernate.cache.use_query_cache true 【开启查询缓存】
也就是说,默认的查询数据是不放在二级缓存中的,如果我们想要把查询出来的数据放到二级缓存,就需要在配置文件中开启
<!-- 开启查询缓存 --> <property name="hibernate.cache.use_query_cache">true</property>
@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(); }
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y
如对本文有疑问, 点击进行留言回复!!
unity的错误解决办法:NullReferenceException: Object reference not set to an instance of an object;tiny proje
Hadoop 之 HDFS (HDFS 数据流的 读写 流程)
听说你一读Spring源码就懵逼?我帮你把架子搭好了,你填就行!
首席架构师推荐:金融保险领域数字化转型实践--如何优雅地修改业务中台中分层应用Maven多模块的版本号?(命令导入式)
[JVM学习之路]一、初识JVM,了解其结构、模型及生命周期
网友评论