ehcache緩存框架
查詢的操作最頻繁,,某個(gè)線程很多的查詢都是重復(fù)的,或者有些數(shù)據(jù)跨線程查詢也是重復(fù)。 問題:造成數(shù)據(jù)庫壓力變大。傳統(tǒng)的數(shù)據(jù)庫查詢效率就不高(網(wǎng)絡(luò)、sql語句復(fù)雜),導(dǎo)致查詢體驗(yàn)不好。 解決:使用緩存機(jī)制。
緩存用什么東西來弄? 傳統(tǒng)有專門緩存框架:ehcache,memcache NoSQL數(shù)據(jù)庫:Redis、MongoDB
EhCache 是一個(gè)純java的進(jìn)程內(nèi)緩存框架,具有快速、精干等特點(diǎn),是Hibernate中默認(rèn)的CachePRovider。
整合Ehcache-優(yōu)化性能-降低查詢數(shù)據(jù)庫的頻率
Spring集成Ehcache: 配置Ehcache緩存管理器(EhcacheManager),將其注入給Spring平臺(tái)緩存管理器(cachemanager),Spring平臺(tái)緩存管理器再注入給Spring緩存注解驅(qū)動(dòng)。代碼中使用注解進(jìn)行緩存。
Shiro集成Ehcache: 配置Ehcache緩存管理器(EhcacheManager),將其注入給Shiro緩存管理器(這里是shiro整合ehcache的緩存管理器),最后將Shiro的緩存管理器注入給Shiro安全管理器
1.通過maven坐標(biāo)導(dǎo)入jar(ehcache和spring的context-support)
<ehcache.version>2.6.10</ehcache.version> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>${ehcache.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency>2.配置applicationContext.xml (Shiro整合ehcache)
<!-- ehchace緩存管理器:ehcache緩存大對(duì)象 --> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <!-- 注入緩存配置文件的位置 --> <property name="configLocation" value="classpath:ehcache.xml"/> </bean> <!-- shiro緩存管理器:整合ehcache --> <bean id="shrioCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <!-- 注入ehcache的緩存管理器 --> <property name="cacheManager" ref="ehcacheManager"/> </bean> <!-- shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- 注入 Realm連接安全數(shù)據(jù)--> <property name="realm" ref="bosRealm"></property> <!-- 注入shiro的緩存管理器 --> <property name="cacheManager" ref="shiroCacheManager"/> </bean> <!--通過配置的方式配置realm對(duì)象,這里參考 --> <!-- <bean id="bosRealm" class="cn.itcast.bos.auth.realm.BosRealm"> 注入緩存具體對(duì)象的名字,該名字在ehcache.xml中配置的 <property name="authenticationCacheName" value="BosShiroCache"/> </bean> -->3.BosRealm中添加注解
@Component("bosRealm") public class BosRealm extends AuthorizingRealm{ //注入緩存名稱 @Value("BosShiroCache")//注入緩存具體對(duì)象的名字,該名字在ehcache.xml中配置的 public void setSuperAuthenticationCacheName(String authenticationCacheName){ super.setAuthenticationCacheName(authenticationCacheName); }4.配置ehcache.xml
<!-- 自定義緩存區(qū)域 --> <cache name=" BosShiroCache " maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </cache> 默認(rèn)的策略: <!-- 硬盤緩存的臨時(shí)路徑 --> <diskStore path="java.io.tmpdir"/> <!-- 默認(rèn)的緩存區(qū)域的緩存策略 maxElementsInMemory:內(nèi)存中最大容納的元素?cái)?shù)量 eternal:對(duì)象是否永生,默認(rèn)是false timeToIdleSeconds:發(fā)呆不用超過多長時(shí)間,over死掉 timeToLiveSeconds:活多久就死掉。 maxElementsOnDisk:硬盤上能存放多少元素 diskExpiryThreadIntervalSeconds:輪詢的時(shí)間,檢查的時(shí)間。 memoryStoreEvictionPolicy:如果緩存滿了怎么辦?LRU,LFU,FIFO persistence strategy:如果內(nèi)存滿了,溢出到硬盤 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache>動(dòng)態(tài)菜單優(yōu)化
減少無用數(shù)據(jù)查詢(減少SQL的發(fā)出)
問題:每次菜單生成的語句太多。生成了很多與功能權(quán)限菜單無關(guān)的語句,如角色等 解決:在Function的實(shí)體類中,使用@JSON(serialize=fase)
對(duì)每個(gè)用戶菜單進(jìn)行緩存
問題:每次刷新整個(gè)頁面都會(huì)重新生成菜單,都會(huì)重新查詢一次數(shù)據(jù)庫。 解決方案:使用緩存。具體:使用spring 整合ehcache的緩存
1.使用maven坐標(biāo)引入jar 略(上面已經(jīng)引過了) 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 <!-- 配置Spring的緩存管理器 --> <bean id="springCacheManagerSpring" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <!-- 注入ehcache的管理器 - --> <property name="cacheManager" ref="ehCacheManager"/> </bean> <!-- 配置緩存的注解驅(qū)動(dòng),它會(huì)自動(dòng)到spring的bean中尋找緩存相關(guān)注解,并使其有效 --> <cache:annotation-driven cache-manager="springCacheManagerSpring"/>3.編寫ehcache.xml,添加一個(gè)新的緩存區(qū)域,如MenuSpringCache
4.在方法上添加注解 提示:spring的緩存管理器默認(rèn)的key是方法名+參數(shù),如果參數(shù)是個(gè)對(duì)象,那么會(huì)發(fā)生每次緩存的key都不一樣,雖然數(shù)據(jù)的一樣的。因此這種情況下,需要手動(dòng)指定key
/** * 獲取用戶權(quán)限 */ @Override //value:緩存區(qū)域,緩存的東西往哪放 //緩存的的key的生成策略 //1.沒有參數(shù),key='0' //2.有1個(gè)參數(shù),那么key是對(duì)象本身,一般是對(duì)象地址 //3.有多個(gè)參數(shù),那么key是多個(gè)對(duì)象的hash值 @Cacheable(value="SpringCache",key="#user.id") public List<Function> findFunctionByUser(User user) {如添加權(quán)限,要清除緩存
/** * 添加功能 */ @Override //清除ehcache的某區(qū)域的所有對(duì)象 @CacheEvict(value="SpringCache",allEntries=true) public void save(Function function) {Hibernate中使用ehcache
1.導(dǎo)入 jar 包:ehcache-1.5.0.jar/ commons-logging.jar/ backport-util-concurrent.jar 2.開啟二級(jí)緩存(我要使用二級(jí)緩存) 3.確定二級(jí)緩存提供商(我要使用哪個(gè)二級(jí)緩存) 4.確定需要緩存內(nèi)容 1>配置需要緩存的類 2>配置需要緩存的集合 5.配置 ehcache 自定義配置文件
引入Maven坐標(biāo)
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>5.0.7.Final</version> </dependency>在 hibernate.cfg.xml 配置緩存,或者交由spring管理,在sessionFactory中配置
開啟二級(jí)緩存
<!-- 開啟二級(jí)緩存 --> <property name="hibernate.cache.use_second_level_cache">true</property>確定緩存提供商
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>確定緩存內(nèi)容
<!-- 類緩存 --> <!-- 指定二級(jí)緩存類 ,以及并發(fā)訪問策略 --> <class-cache usage="read-write" class="cn.aric.domain.User"/> <!-- 集合緩存 --> <collection-cache usage="read-write" collection="cn.aric.doain.Customer.orderSet"/>ehcache 配置文件
文件名: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>測試
//測試二級(jí)緩存是否配置成功 @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(); }查詢緩存
查詢緩存默認(rèn)不使用。需要手動(dòng)開啟 查詢緩存:將 HQL 語句與 查詢結(jié)果進(jìn)行綁定。通過 HQL 相同語句可以緩存內(nèi)容。 默認(rèn)情況 Query 對(duì)象只將查詢結(jié)果存放在一級(jí)和二級(jí)緩存,不從一級(jí)或二級(jí)緩存獲取。 查詢緩存就是讓 Query 可以從二級(jí)緩存獲得內(nèi)容。
<!-- 開啟查詢緩存 --> <property name="hibernate.cache.use_query_cache">true</property> @Test public void demo(){ // 查詢緩存 Session s1 = factory.openSession(); s1.beginTransaction(); //1 query查詢 Query q1 = s1.createQuery("from Customer"); //設(shè)置查詢緩存為true q1.setCacheable(true); List<Customer> a1 = q1.list(); for (Customer c1 : a1) { System.out.println(c1); } //2 cid =1 -- 一級(jí)緩存獲得 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 -- 二級(jí)緩存獲得 Customer customer2 = (Customer) s2.get(Customer.class, 1); System.out.println(customer2); //3 query查詢 Query q2 = s2.createQuery("from Customer"); q2.setCacheable(true); List<Customer> a2 = q2.list(); for (Customer c2 : a2) { System.out.println(c2); } s2.getTransaction().commit(); s2.close(); }