HashMap与redis在项目中的应用

Posted songstar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashMap与redis在项目中的应用相关的知识,希望对你有一定的参考价值。

刚从.net转java三个月,这里记录一下在java项目中使用缓存的学习。

因为项目之前的开发人员离职了,在之前的项目上进行维护,对应从来没有接触过java的小白,只能自己多看多理解多动手了。

这个项目原来是没有用java真正意义上的缓存,而是用的静态的HashMap,但是在性能测试的过程中出现了死锁的过程,因为hashmap是不安全的线程,建议使用ConcurrentHashMap这个和.net的Dictonary很像。因为性能测试不通过,所以后来加了redis,其实java的一级缓存ehcache也是很好的,因为项目到了后期阶段,项目时间紧就没改ehcahe(这个.net的asp.net cache一样)。

言归正传:

hashmap的使用方法:

首先定义一个InitCacheData类,里面填充各种属性和方法。

技术分享图片
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的使用方法:

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

 

 

 

 

 

以上是关于HashMap与redis在项目中的应用的主要内容,如果未能解决你的问题,请参考以下文章

Redis 在 Web 项目中的应用与实践

如何在Java中应用Redis操作HashMap

201671010432词频统计软件项目报告

Liunx下Redis集群的安装与测试,以及项目中的应用(redis中对象和集合的储存)。

如何在Java中应用Redis操作HashMap

什么意思 在HashMap之前 ? Java中的泛型[重复]