查询的操作最频繁,,某个线程很多的查询都是重复的,或者有些数据跨线程查询也是重复。
问题:造成数据库压力变大。传统的数据库查询效率就不高(网络、sql语句复杂),导致查询体验不好。
解决:使用缓存机制。
缓存用什么东西来弄?
传统有专门缓存框架:ehcache,memcache
NoSQL数据库:Redis、MongoDB
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
Spring集成Ehcache:
配置Ehcache缓存管理器(EhcacheManager),将其注入给Spring平台缓存管理器(cachemanager),Spring平台缓存管理器再注入给Spring缓存注解驱动。代码中使用注解进行缓存。
Shiro集成Ehcache:
配置Ehcache缓存管理器(EhcacheManager),将其注入给Shiro缓存管理器(这里是shiro整合ehcache的缓存管理器),最后将Shiro的缓存管理器注入给Shiro安全管理器
<ehcache.version>2.6.10ehcache.version>
<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcache-coreartifactId>
<version>${ehcache.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>${spring.version}version>
dependency>
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
bean>
<bean id="shrioCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm">property>
<property name="cacheManager" ref="shiroCacheManager"/>
bean>
@Component("bosRealm")
public class BosRealm extends AuthorizingRealm{
//注入缓存名称
@Value("BosShiroCache")//注入缓存具体对象的名字,该名字在ehcache.xml中配置的
public void setSuperAuthenticationCacheName(String authenticationCacheName){
super.setAuthenticationCacheName(authenticationCacheName);
}
<cache name=" BosShiroCache "
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
cache>
默认的策略:
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
defaultCache>
问题:每次菜单生成的语句太多。生成了很多与功能权限菜单无关的语句,如角色等
解决:在Function的实体类中,使用@JSON(serialize=fase)
问题:每次刷新整个页面都会重新生成菜单,都会重新查询一次数据库。
解决方案:使用缓存。具体:使用spring 整合ehcache的缓存
1.使用maven坐标引入jar
略(上面已经引过了)
2.配置ApplicationContext.xml
xmlns:cache="http://www.springframework.org/schema/cache"
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
<bean id="springCacheManagerSpring" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehCacheManager"/>
bean>
<cache:annotation-driven cache-manager="springCacheManagerSpring"/>
3.编写ehcache.xml,添加一个新的缓存区域,如MenuSpringCache
4.在方法上添加注解
提示:spring的缓存管理器默认的key是方法名+参数,如果参数是个对象,那么会发生每次缓存的key都不一样,虽然数据的一样的。因此这种情况下,需要手动指定key
/**
* 获取用户权限
*/
@Override
//value:缓存区域,缓存的东西往哪放
//缓存的的key的生成策略
//1.没有参数,key='0'
//2.有1个参数,那么key是对象本身,一般是对象地址
//3.有多个参数,那么key是多个对象的hash值
@Cacheable(value="SpringCache",key="#user.id")
public List findFunctionByUser(User user) {
如添加权限,要清除缓存
/**
* 添加功能
*/
@Override
//清除ehcache的某区域的所有对象
@CacheEvict(value="SpringCache",allEntries=true)
public void save(Function function) {
1.导入 jar 包:ehcache-1.5.0.jar/ commons-logging.jar/ backport-util-concurrent.jar
2.开启二级缓存(我要使用二级缓存)
3.确定二级缓存提供商(我要使用哪个二级缓存)
4.确定需要缓存内容
1>配置需要缓存的类
2>配置需要缓存的集合
5.配置 ehcache 自定义配置文件
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-ehcacheartifactId>
<version>5.0.7.Finalversion>
dependency>
在 hibernate.cfg.xml 配置缓存,或者交由spring管理,在sessionFactory中配置
<property name="hibernate.cache.use_second_level_cache">trueproperty>
"hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
<class-cache usage="read-write" class="cn.aric.domain.User"/>
<collection-cache usage="read-write" collection="cn.aric.doain.Customer.orderSet"/>
文件名:ehcache.xml
参考官方文件配置
<ehcache>
<diskStore path="f:cache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="hibernateCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
ehcache>
//测试二级缓存是否配置成功
@Test
public void test(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取session1
Session session1 = sessionFactory.openSession();
Transaction tx = session1.beginTransaction();
User user1 = session1.get(User.class, 10L);
System.out.println(user1.getUser_code());
tx.commit();
session1.close();
//获取session2
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
User user2 = session2.get(User.class, 10L);
System.out.println(user2.getUser_code());
tx2.commit();
session2.close();
}
查询缓存默认不使用。需要手动开启
查询缓存:将 HQL 语句与 查询结果进行绑定。通过 HQL 相同语句可以缓存内容。
默认情况 Query 对象只将查询结果存放在一级和二级缓存,不从一级或二级缓存获取。
查询缓存就是让 Query 可以从二级缓存获得内容。
"hibernate.cache.use_query_cache">true
@Test
public void demo(){
// 查询缓存
Session s1 = factory.openSession();
s1.beginTransaction();
//1 query查询
Query q1 = s1.createQuery("from Customer");
//设置查询缓存为true
q1.setCacheable(true);
List a1 = q1.list();
for (Customer c1 : a1) {
System.out.println(c1);
}
//2 cid =1 -- 一级缓存获得
Customer customer = (Customer) s1.get(Customer.class, 1);
System.out.println(customer);
s1.getTransaction().commit();
s1.close();
System.out.println("----------");
Session s2 = factory.openSession();
s2.beginTransaction();
//2 cid =1 -- 二级缓存获得
Customer customer2 = (Customer) s2.get(Customer.class, 1);
System.out.println(customer2);
//3 query查询
Query q2 = s2.createQuery("from Customer");
q2.setCacheable(true);
List a2 = q2.list();
for (Customer c2 : a2) {
System.out.println(c2);
}
s2.getTransaction().commit();
s2.close();
}