刚从.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()); } } }
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
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>
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
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>
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); } }
6.具体使用
if(redisCache.get(answerkey)!=null) { redisCache.remove(answerkey); } redisCache.set(answerkey,reCombinsList);
原文地址:https://www.cnblogs.com/songStar/p/9359176.html
时间: 2024-10-07 06:35:51