一、一级缓存
Hibernate使用一级缓存来缓存Session所查询的对象。一级缓存是Hibernate中由SessionFactory维护的一个缓存区域。在同一个Session中,如果查询多次相同的对象,则只有第一次查询时会访问数据库,后续的查询会直接从缓存中读取,以提高查询速度。如果Session关闭了,一级缓存也会被销毁。下面是一段使用Hibernate一级缓存的代码:
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); // 第一次查询 Person person = (Person) session.get(Person.class, 1); System.out.println(person); // 第二次查询 person = (Person) session.get(Person.class, 1); System.out.println(person); tx.commit(); session.close();
上面的代码中,第二次查询实际上并没有执行任何SQL语句,因为Hibernate一级缓存会直接返回缓存中的对象。
二、二级缓存
一级缓存只作用于Session级别,对于多个Session之间的缓存共享无法满足要求,因此Hibernate引入了二级缓存。二级缓存是基于SessionFactory的,当多个Session共享一个SessionFactory时,它们都可以访问同一个缓存区域。二级缓存可以提高查询效率,因为如果某个对象在缓存中已经存在,则查询时无需再访问数据库。下面是一段使用Hibernate二级缓存的代码:
// 开启二级缓存 cfg.setProperty("hibernate.cache.use_second_level_cache", "true"); // 指定使用EhCache缓存 cfg.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory"); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session1 = sessionFactory.openSession(); Transaction tx1 = session1.beginTransaction(); // 第一次查询 Person person1 = (Person) session1.get(Person.class, 1); System.out.println(person1); tx1.commit(); session1.close(); Session session2 = sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); // 第二次查询 Person person2 = (Person) session2.get(Person.class, 1); System.out.println(person2); tx2.commit(); session2.close(); // 结果相同,没有执行SQL语句 System.out.println(person1 == person2);
在上面的代码中,开启了二级缓存并指定了使用EhCache作为缓存。由于二级缓存实现了多个Session之间的缓存共享,因此第二次查询时并没有执行SQL语句,而是直接从缓存中获取了数据。
三、缓存策略
Hibernate缓存的策略可以根据不同的应用场景来选择,Hibernate提供了多种缓存策略,分别是读写、只读、事务性、非严格读写等。根据具体的使用情况来选择缓存策略,可以提高查询效率并降低数据库访问压力。下面是几种常用的缓存策略。读写缓存策略
读写缓存策略适用于更新比较频繁的数据,可以将查询结果存放到缓存中,同时也会在缓存中存放已修改但未提交的对象。这种缓存策略可以提高读写并发性能,但是会增加缓存管理的复杂度。使用此缓存策略时,需要在配置文件中设置相应的缓存属性:cfg.setProperty("hibernate.cache.use_second_level_cache", "true"); cfg.setProperty("hibernate.cache.use_query_cache", "true"); cfg.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider"); // 配置更新策略 cfg.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"); cfg.setProperty("hibernate.cache.region.person.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"); cfg.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Person person = (Person) session.get(Person.class, 1); person.setName("Johnny"); session.update(person); tx.commit(); session.close();
只读缓存策略
只读缓存策略适用于只有查询操作的应用场景,这种缓存策略可以提高并发性能。使用此缓存策略时,需要在配置文件中设置相应的缓存属性,并且在查询语句中使用“setCacheable(true)”方法将查询结果存放到缓存中:cfg.setProperty("hibernate.cache.use_second_level_cache", "true"); cfg.setProperty("hibernate.cache.use_query_cache", "true"); cfg.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory"); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); // 使用只读缓存策略 Query query = session.createQuery("from Person where age > 20"); query.setCacheable(true); Listlist = query.list(); session.close();
非严格读写缓存策略
非严格读写缓存策略适用于访问频率较低但更新比较频繁的数据,既可以提高并发性能,又可以保证数据的一致性。使用此缓存策略时,需要在配置文件中设置相应的缓存属性:cfg.setProperty("hibernate.cache.use_second_level_cache", "true"); cfg.setProperty("hibernate.cache.use_query_cache", "true"); cfg.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider"); // 配置更新策略 cfg.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"); cfg.setProperty("hibernate.cache.region.person.factory_class", "org.hibernate.cache.ehcache.NonStrictReadWriteEhcacheRegionFactory"); cfg.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.NonStrictReadWriteEhcacheRegionFactory"); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Person person = (Person) session.get(Person.class, 1); person.setName("Johnny"); session.update(person); tx.commit(); session.close();