HashMap與redis在項目中的應用

剛從.net轉java三個月,這裏記錄一下在java項目中使用緩存的學習。java

由於項目以前的開發人員離職了,在以前的項目上進行維護,對應歷來沒有接觸過java的小白,只能本身多看多理解多動手了。node

這個項目原來是沒有用java真正意義上的緩存,而是用的靜態的HashMap,可是在性能測試的過程當中出現了死鎖的過程,由於hashmap是不安全的線程,建議使用ConcurrentHashMap這個和.net的Dictonary很像。由於性能測試不經過,因此後來加了redis,其實java的一級緩存ehcache也是很好的,由於項目到了後期階段,項目時間緊就沒改ehcahe(這個.net的asp.net cache同樣)。web

言歸正傳:redis

hashmap的使用方法:spring

首先定義一個InitCacheData類,裏面填充各類屬性和方法。sql

 

建議用這種數據庫

public class InitCacheData {
    private static InitCacheData instance;

    private InitCacheData() {
    }

    /**
     * description 單例模式
     * @param @return
     * @return InitCacheData
     */
    public static InitCacheData getInstance() {
        synchronized (InitCacheData.class) {
            if (instance == null) {
                instance = new InitCacheData();
            }
            return instance;
        }
    }
    
    /**
     * 初始化數據的緩存,key:數據類型,value:數據(key:實體類主鍵的值,value對應的實體類)
     */
    private Map<CacheType, Map<Integer, Object>> cacheData = new HashMap<CacheType, Map<Integer, Object>>();
    private Map<CacheType, Map<Integer, List<Object>>> cacheTreeData = new HashMap<CacheType, Map<Integer, List<Object>>>();
    private Map<CacheType, Map<String, Object>> cacheItemMappingData = new HashMap<CacheType, Map<String, Object>>();
    
    private Map<String,List<SingleTrainStudentAnswer>> cacheAnswerData = new ConcurrentHashMap<String,List<SingleTrainStudentAnswer>>();  
    private Map<CacheType,List<ProjectItem>> projectItemData = new HashMap<CacheType,List<ProjectItem>>();


    /**
     * @description 初始化數據的類型
     */
    public enum CacheType {
        CLASS, MAJOR, COLLEGE, COURSE,USER_INFO,KNOW_POINT,STUDENT,TEACHER,ITEMMAPPING,PARAMETER_TYPE,TRDCO,ANSWER,PROJECTITEM,BASEITEMS
    };

    public Map<Integer, Object> getCacheData(CacheType dataType){
        return this.cacheData.get(dataType);
    }
    
    public Map<CacheType, List<ProjectItem>> getBasicItemsData() {
        return basicItemsData;
    }
    

    
    /**
     * description 初始化數據執行的方法
     * @param 
     * @return void
     */
    public void initData() {

        initCourseData();
        initBasicItemsData();
        

    }
    
    //獲取學生練習列表:對應登陸後的練習菜單
    private void initBasicItemsData() {
        IProjectItemService projectItemService = (IProjectItemService) SpringContextUtil.getBean("projectItemService");
        List<ProjectItem> list = projectItemService.getBasicItems();
        if(basicItemsData.get(CacheType.BASEITEMS)!=null) {
            basicItemsData.get(CacheType.BASEITEMS).clear();
        }
        basicItemsData.put(CacheType.BASEITEMS,list);
    }


    private void initCourseData() {
        ICourseService courseService = (ICourseService)SpringContextUtil.getBean("courseService");
        List<Course> courseList = courseService.findAll();
        Map<Integer, Object> courseMap = new HashMap<Integer, Object>(courseList.size());
        Iterator<Course> courseIt = courseList.iterator();
        Course course = null;
        while(courseIt.hasNext()){
            course = courseIt.next();
            courseMap.put(course.getId(), course);
        }
        
        if(cacheData.get(CacheType.COURSE) != null){
            cacheData.get(CacheType.COURSE).clear();
        }
        cacheData.put(CacheType.COURSE, courseMap);
    }

    
    /**
     * @description 經過遞歸得到全部選中節點下面的全部節點id
     * @param 
     * @return void
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void getChildNodes(List<Integer> idsList,int nodeId){
        Map<Integer,List<Object>> knowPointMap = cacheTreeData.get(CacheType.KNOW_POINT);
        if(knowPointMap.containsKey(nodeId)){
            List<KnowPoint> knowPointList = (List)knowPointMap.get(nodeId);
            for(KnowPoint know : knowPointList){
                idsList.add(know.getId());
                getChildNodes(idsList,know.getId());
            }
        }
    
    }
    
View Code

redis的使用方法:express

1.在maven項目中添加引用依賴緩存

 1 <dependency>  
 2             <groupId>org.springframework.data</groupId>  
 3             <artifactId>spring-data-redis</artifactId>  
 4             <version>1.5.0.RELEASE</version>
 5         </dependency> 
 6         <dependency>
 7             <groupId>redis.clients</groupId>
 8             <artifactId>jedis</artifactId>
 9             <version>2.9.0</version>
10         </dependency>
11         
View Code

2.要建立spring-redis.xml安全

<beans     xmlns="http://www.springframework.org/schema/beans" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p" 
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
               ">
    
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="minIdle" value="${redis.minIdle}" /> 
        <property name="maxTotal" value="${redis.maxTotal}" />  
        <property name="maxWaitMillis" value="${redis.max-wait-millis}" />  
    </bean>  
      
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  
        p:host-name="${redis.host}" 
        p:port="${redis.port}" 
        p:password="${redis.password}"  
        p:database="0" 
        p:timeout="${redis.timeout}"
        p:pool-config-ref="poolConfig"/>  
      
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">  
        <property name="connectionFactory"   ref="connectionFactory" /> 
        <property name="defaultSerializer"   ref="jdkSerializationRedisSerializer" />  
    </bean>   
    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">  
        <property name="connectionFactory"   ref="connectionFactory" />  
    </bean>  
    <bean id="jdkSerializationRedisSerializer" class=" org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
</beans>  
View Code

3.添加redis.properties配置文件

#redis setting  
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
redis.maxIdle=100
redis.maxActive=300
redis.maxWait=1000
redis.testOnBorrow=true
redis.timeout=100000

fep.local.cache.capacity =10000
View Code

4.在spring-context.xml文件中導入redis配置 <import resource="spring-redis.xml"/> 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:task="http://www.springframework.org/schema/task" 
       xmlns:jms="http://www.springframework.org/schema/jms"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/task 
       http://www.springframework.org/schema/task/spring-task-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
       http://www.springframework.org/schema/jms
       http://www.springframework.org/schema/jms/spring-jms-3.2.xsd">
    <!-- 啓用annotation方式 -->
    <task:annotation-driven scheduler="myScheduler" />

    <!-- 配置任務線程池 -->
    <task:scheduler id="myScheduler" pool-size="5" />
    <context:annotation-config/>

    <!-- 設置屬於Spring管理的類 -->
    <context:component-scan base-package="com.gta">
        <!-- 排除com.gta.demo.controller包下的類,由SpringMVC來管理 -->
        <context:exclude-filter type="regex" expression="com.gta.kjzh.controller.*"/>
    </context:component-scan>

    <!-- 設置項目中能夠獲取到的properties配置文件 -->
    <context:property-placeholder location="classpath*:/config/*.properties"/>

    <!-- 設置Druid數據源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <!-- 數據源URL -->
        <property name="url" value="${url}"/>
        <!-- 數據庫用戶名 -->
        <property name="username" value="${db.username}"/>
        <!-- 數據庫密碼 -->
        <property name="password" value="${db.password}"/>
        <!-- 數據庫驅動 -->
        <property name="driverClassName" value="${driverClassName}"/>

        <!-- 屬性類型是字符串,經過別名的方式配置擴展插件,經常使用的插件有: 監控統計用的filter:stat 日誌用的filter:log4j 防護sql注入的filter:wall -->
        <property name="filters" value="${druid.filters}"/>

        <!-- 最大鏈接池數量 -->
        <property name="maxActive" value="${maxActive}"/>
        <!-- 初始化時創建物理鏈接的個數 -->
        <property name="initialSize" value="${initialSize}"/>
        <!-- 獲取鏈接時最大等待時間,單位毫秒 -->
        <property name="maxWait" value="${maxWait}"/>
        <!-- 啓用非公平鎖 -->
        <property name="useUnfairLock" value="true"/>
        <!-- 最小鏈接池數量 -->
        <property name="minIdle" value="${minIdle}"/>

        <!-- 有兩個含義:
            1) Destroy線程會檢測鏈接的間隔時間
            2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明 -->
        <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}"/>

        <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}"/>

        <!-- 用來檢測鏈接是否有效的sql,要求是一個查詢語句,若是validationQuery爲null,testOnBorrow、testOnReturn、 testWhileIdle都不會其做用 -->
        <property name="validationQuery" value="${validationQuery}"/>
        <!-- 建議配置爲true,不影響性能,而且保證安全性。 申請鏈接的時候檢測,若是空閒時間大於 timeBetweenEvictionRunsMillis,執行validationQuery檢測鏈接是否有效。-->
        <property name="testWhileIdle" value="${testWhileIdle}"/>
        <!-- 申請鏈接時執行validationQuery檢測鏈接是否有效,作了這個配置會下降性能。 -->
        <property name="testOnBorrow" value="${testOnBorrow}"/>
        <!-- 歸還鏈接時執行validationQuery檢測鏈接是否有效,作了這個配置會下降性能 -->
        <property name="testOnReturn" value="${testOnReturn}"/>
        <!-- 要啓用PSCache,必須配置大於0,當大於0時,poolPreparedStatements自動觸發修改成true。在Druid中,不會存在Oracle下PSCache佔用內存過多的問題,能夠把這個數值配置大一些,好比說100 -->
        <!--<property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}"/>-->
        <!-- 打開removeAbandoned功能 -->
        <property name="removeAbandoned" value="${removeAbandoned}"/>
        <!-- 1800秒,也就是30分鐘 -->
        <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}"/>
        <!-- 關閉abanded鏈接時輸出錯誤日誌 -->
        <property name="logAbandoned" value="${logAbandoned}"/>
    </bean>

    <!-- spring上傳文件配置,這裏申明的id必須爲multipartResolver -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="314572800" />
    </bean> 
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
        <property name="dataSource" ref="dataSource"></property>  
    </bean>  

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="hibernateProperties">
            <props>
                <!-- 設置數據庫方言 -->
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <!--<prop key="hibernate.current_session_context_class">${hibernate.current_session}</prop>-->
                <!-- 設置是否在控制檯輸出sql語句 -->
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <!-- 輸出格式化的sql語句 -->
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <!-- 設置項目啓動時,hibernate檢查數據庫和實體類是否匹配 -->
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                
                <!-- hibernate ehcache 配置  EhCacheRegionFactory-->
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory </prop> 
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                 <!-- 二級緩存配置文件路徑 /resources/hibernate-->   
                <prop key="net.sf.ehcache.configurationResourceName">/config/ehcache.xml</prop>
                
            </props>
        </property>
        <!-- 掃描受Hibernate管理的實體類所在的包-->
        <property name="packagesToScan" value="com.gta.kjzh.*"/>
    </bean>
    
    <bean id="genericDao" class="com.gta.kjzh.sdk.base.dao.HibernateGenericDAO"></bean>
    
    <!-- 設置spring使用Hibernate的事務處理方式 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <!-- 設置事務註解使用spring事務管理的方式 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
    <!-- 通用springMVC攔截器的設置 
    <bean id="springMVCInterceptor" class="com.gta.filter.SpringMVCInterceptor"></bean>     
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">     
        <property name="interceptors">     
            <list>     
                <ref bean="springMVCInterceptor"/>     
            </list>     
        </property>     
    </bean> 
    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <tx:attributes>
          <tx:method name="get*" read-only="true" propagation="REQUIRED"/>
          <tx:method name="find*" read-only="true" propagation="REQUIRED"/>
          <tx:method name="save*" propagation="REQUIRED"/>
          <tx:method name="update*" propagation="REQUIRED"/>
          <tx:method name="remove*" propagation="REQUIRED"/>
          <tx:method name="add*" propagation="REQUIRED"/>
          <tx:method name="*"/>
       </tx:attributes>
    </tx:advice>
    
    <aop:config proxy-target-class="true">
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.gta.kjzh.*.service..*.*(..))"/>
    </aop:config>-->
    <!-- <import resource="activemq.xml"/> -->
    <import resource="spring-redis.xml"/> 
    <!-- <import resource="spring-quartz-answer.xml"/> 
    <import resource="spring-quartz.xml"/>  -->
</beans>
View Code

5.編輯RedisCache類,裏面放有redis的增刪改查操做。

package com.kjzh.redis.cache;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import com.gta.kjzh.util.SerializeUtils;

import net.sf.ehcache.CacheException;
@Component
public class RedisCache<K, V> {
    private static String redisCode = "utf-8";
    private String prefix;
    @Autowired
    private RedisTemplate<byte[], V> redisTemplate;
    
    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;
    
    public Set<String> getKeys(String keyPattern) {
        return stringRedisTemplate.keys(keyPattern);
    }
    
    public String getString(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
    
    public void setString(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }
    

    public V get(K key) {
        byte[] bkey = getByteKey(key);
        return redisTemplate.opsForValue().get(bkey);
    }
    
    public void set(K key, V value) {
        byte[] bkey = getByteKey(key);
        redisTemplate.opsForValue().set(bkey, value);
    }
    
    public void remove(K key) {
        byte[] bkey = getByteKey(key);
        redisTemplate.delete(bkey);
    }

    public void set(K key, V value, long timeout) {
        
         byte[] bkey = getByteKey(key);
        redisTemplate.opsForValue().set(bkey, value, timeout, TimeUnit.SECONDS);
    }
    
     String get(K key, long start, long end){
         byte[] bkey = getByteKey(key);
         return redisTemplate.opsForValue().get(bkey,start,end);
     }
     Long size(K key){
         byte[] bkey = getByteKey(key);
         return redisTemplate.opsForValue().size(bkey);
     }
     
     List<V> range(K key, long start, long end){
         byte[] bkey = getByteKey(key);
         return redisTemplate.opsForList().range(bkey,start,end);
     }
     
     public void clear() throws CacheException {
         redisTemplate.getConnectionFactory().getConnection().flushDb();
     }
     
     public List<V> getListValue(K key) {
             byte[] bkey = getByteKey(key);
            ListOperations<byte[], V> list = redisTemplate.opsForList();
            return redisTemplate.opsForList().range(bkey, 0,list.size(bkey));

     }

     
     private byte[] getByteKey(K key){
            if(key instanceof String){
                String preKey = this.prefix + key;
                return preKey.getBytes();
            }else{
                return SerializeUtils.serialize(key);
            }
        }
     
     public String getPrefix() {
            return prefix;
     }
     
     /**
     * 批量刪除對應的value
     * 
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量刪除key
     * 
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }
    
    /**
     * 判斷緩存中是否有對應的value
     * 
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

}
View Code

6.具體使用

if(redisCache.get(answerkey)!=null) {
                redisCache.remove(answerkey);
            }
            redisCache.set(answerkey,reCombinsList);
View Code
相關文章
相關標籤/搜索