发表于: 2021-09-21 23:19:52

2 753


一,今天完成的事情

任务六。


1,我设置了适合我的RedisConfig文件,配置合适的Bean。Redis涉及转换数据类型的问题,目前用的fastJson。Type能自动转换也设置好

ParserConfig.getGlobalInstance().addAccept("com.nicole.tileslogin.entity");

最终用的注解配置是:

package com.nicole.tileslogin.config;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
* Created by daixiaoming on 2018-12-05.
*/
@Configuration
@PropertySource("classpath:redis.properties")
public class RedisConfig {

@Value("${hostName}")
private String hostName;

   @Value("${port}")
private int port;

   @Value("${pool.maxIdle}")
private int maxIdle;

   @Value("${pool.minIdle}")
private int minIdle;

   @Value("${pool.maxWaitMillis}")
private int maxWaitMillis;

   @Value("${pool.maxTotal}")
private int maxTotal;

   @Bean
   public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
       redisStandaloneConfiguration.setHostName(hostName);
       redisStandaloneConfiguration.setPort(port);

       GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
       poolConfig.setMaxIdle(maxIdle);
       poolConfig.setMinIdle(minIdle);
       poolConfig.setMaxWaitMillis(maxWaitMillis);
       poolConfig.setMaxTotal(maxTotal);

       LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(5000))
.shutdownTimeout(Duration.ZERO)
.poolConfig(poolConfig)
.build();

       LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettucePoolingClientConfiguration);
       lettuceConnectionFactory.setShareNativeConnection(false);

       return lettuceConnectionFactory;
   }

@Bean
   public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
       redisTemplate.setConnectionFactory(redisConnectionFactory);

       // 设置键(key)的序列化采用StringRedisSerializer
       StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
       redisTemplate.setKeySerializer(stringRedisSerializer);
       redisTemplate.setHashKeySerializer(stringRedisSerializer);


       FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
       FastJsonConfig fastJsonConfig = new FastJsonConfig();
       fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteClassName);
       fastJsonRedisSerializer.setFastJsonConfig(fastJsonConfig);
       // 全局开启AutoType,不建议使用
//         ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
       // 建议使用这种方式,小范围指定白名单
//        ParserConfig.getGlobalInstance().addAccept("com.doodl6.");
       ParserConfig.getGlobalInstance().addAccept("com.nicole.tileslogin.entity");

       // 设置值(value)的序列化采用FastJsonRedisSerializer
       redisTemplate.setValueSerializer(fastJsonRedisSerializer);
       redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
       redisTemplate.afterPropertiesSet();
       return redisTemplate;
   }

}


我的Redis测试用的是ValueOperations<String, List<ExcellentStudent>> valueOperations,限制类型。也可以用ListOperations,但是特地注意如果用这个,要考虑好类型转换的问题,比较会可能有类型转换问题。如果下面代码的list就是要转化的变量,要变成List<User>类型

objectMapper.convertValue(lists, new TypeReference<List<User>>() { });

我的test,存好后,取数据也成功。顺利把取出的数据封装成

List<ExcellentStudent>



2,测试,现在的方法可用,当然最好全部都是注入。

package com.nicole.tileslogin;

import com.nicole.tileslogin.config.RedisConfig;
import com.nicole.tileslogin.entity.ExcellentStudent;
import com.nicole.tileslogin.service.ExcellentStudentService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-mybatis.xml"})
public class RedisConfigTest {
@Autowired
   private ExcellentStudentService excellentStudentService;
   @Autowired
   private RedisTemplate redisTemplate;

//    private ListOperations<String, List<ExcellentStudent>> opsForList;

   private ValueOperations<String, List<ExcellentStudent>> valueOperations;

   @Before
   public void setUp() throws Exception{
//        opsForList = redisTemplate.opsForList();
       valueOperations = redisTemplate.opsForValue();
   }

@Test
   @Transactional
   @Rollback(true)
public void getExcStudentsTest(){
//只看前4个记录
       int offset = 0;
       int limit = 4;
       String key = "studentList";
       List<ExcellentStudent> studentList = new ArrayList<>();
       boolean hasKey = redisTemplate.hasKey(key);
       if(hasKey){
studentList = valueOperations.get(key);
           int size = studentList.size();
           for (int i = 0; i < size; i++) {
System.out.println("从缓存中获取数据:"+ studentList.get(i).getName());
           }

System.out.println("-----------------------------");
       }else{
studentList =
excellentStudentService.queryAllByLimit( offset, limit);
           System.out.println("查询数据库获取数据:"+studentList.get(0).getName());
           valueOperations.set("studentList", studentList);
           System.out.println("------------写入缓存---------------------");
       }
}

}


存储好后成功取的结果,成功,我选择直接打印出来


3,将Redis缓存加入service层

@Service("excellentStudentService")
public class ExcellentStudentServiceImpl implements ExcellentStudentService {
@Autowired
   private ExcellentStudentDao excellentStudentDao;
   @Autowired
   private RedisTemplate redisTemplate;

   /**
    * 通过ID查询单条数据
    *
    * @param id 主键
    * @return 实例对象
    */
   @Override
   public ExcellentStudent queryById(Long id) {
return this.excellentStudentDao.queryById(id);
   }

/**
    * 查询多条数据
    *
    * @param offset 查询起始位置
    * @param limit 查询条数
    * @return 对象列表
    */
   @Override
   public List<ExcellentStudent> queryAllByLimit(int offset, int limit) {
String key = "studentList";
       ValueOperations<String, List<ExcellentStudent>> valueOperations = redisTemplate.opsForValue();
       List<ExcellentStudent> studentList = new ArrayList<>();
       boolean hasKey = redisTemplate.hasKey(key);
       if(hasKey){
studentList = valueOperations.get(key);
       }else{
studentList =
excellentStudentDao.queryAllByLimit( offset, limit);
           if(studentList.size() < 1) {
valueOperations.set("studentList", null);
           }
valueOperations.set("studentList", studentList);
       }
return studentList;
   }


运行这个

queryAllByLimit

方法有关的controller层,成功访问,而且在缓存那个打印到控制台过,是在Redis缓存访问。

还是成功访问网页。


4,但是,在本地用JMeter压力测试,发现本来不会出现错误的100并发,用Redis出现了错误。我的图片在数据库中存的是路径,所以通过Redis就算是图片路径拿图片。

对我的本地Windows压力也过大。


5,JMeter测试在云Linux上的http://47.111.153.120/tiles_login/excellentStudent/salaryDesc


100没有错误


500远程压力比较明显


6,5的远程Linux吞吐量不行。先不测其它了。先测一测Json的返回格式在本地,是不是吞吐量赶紧能上去。

@RequestMapping(value = "/salaryDescJson", method = RequestMethod.GET)
@ResponseBody
public Map<String, Object> excellentStudentJson(){
int offset = 0;
   int limit = 4;
   List<ExcellentStudent> studentList = excellentStudentService.queryAllByLimit( offset, limit);
   if (null == studentList) {
return Restful.set(400, "查找优秀学员失败" );
   } else {
return Restful.set(200, "查找优秀学员成功", studentList);
   }
}


有缓存本地100表现都很差


注释,不用缓存,还是原来的

return excellentStudentDao.queryAllByLimit(offset,limit);

测试返回JSON的带

@ResponseBody

没有我的Redis代码,本地反而跑得正常了

本地不用Redis 500也正常


1000有limit的有问题正常


二,今天问题

数据类型转换要小心,要花心思。就算用fastJson等工具,要做明白不算简单。

网站吞吐很差。


三,今天的收获

Redis拦在MySQL前面。类型使用,泛型实战。

xml配置和注解文件用注解配置转换。


四,明天的计划

任务6

在Linux上安装Redis,并测试war包。比较有和没有Redis的表现情况。

换没有offset,limit的相对简单的语句测试。redis是有用的。





返回列表 返回列表
评论

    分享到