Springboot与Redis Cache深度整合

目录

  1. Springboot项目创建
  2. Springboot与Redis整合
  3. Springboot与Mybatis整合
  4. Springboot与Cache整合使用
  5. Redis作为mybatis二级缓存
  6. Redis分布式session共享

Springboot项目创建

1.打开IDEA 创建工程

在这里插入图片描述

2.选择IDEA中Spring initilazier
在这里插入图片描述

3.设置自己的包命名规范
在这里插入图片描述

4.勾选Web -> Spring Web -> Next -> Finish创建工程
在这里插入图片描述
5.创建对应的文件夹,后面内容基于此文件夹进行配置,工程结构
在这里插入图片描述

Springboot与Redis整合

1.打开pom.xml,引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.再application.yml配置

spring:
  redis:
    port: 6379
    host: xxx.xxx.xx.xx

3.再config文件夹下创建RedisConfig.java 进行redisTemplate初步调用

package com.gcxzflgl.redis.config;


/**
 * @author gcxzf$
 * @version : RedisConfiguration$, v 0.1 2020/6/13$ 15:39$ gcxzf$ Exp$
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String,String> restTemplate(RedisConnectionFactory factory){
        RedisTemplate<String,String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
}

4.编写测试案例测试redisTemplate保存到redis中

package com.gcxzflgl.redis;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class RedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("gcx","is handsonn boy");
    }

}

5.查看redis中存在测试用例的key,因为我们暂未配置序列化方式,使用的是默认JdkSerializationRedisSerializer序列化方式,后面会逐步配置自己能看懂的序列化方式
在这里插入图片描述

Springboot与Mybatis整合

1.再pom.xml中添加mybatis相关依赖

<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.47</version>
 </dependency>
 <dependency>
     <groupId>org.mybatis.spring.boot</groupId>
     <artifactId>mybatis-spring-boot-starter</artifactId>
     <version>1.3.0</version>
 </dependency>

 <dependency>
     <groupId>org.mybatis.generator</groupId>
     <artifactId>mybatis-generator-core</artifactId>
     <scope>test</scope>
     <version>1.3.2</version>
     <optional>true</optional>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-jdbc</artifactId>
 </dependency>

 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>druid</artifactId>
     <version>1.1.10</version>
 </dependency>

 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.7</version>
 </dependency>

2.再application.yml中配置如下

spring:
  datasource:
    url: jdbc:mysql://xxx.xxx.xx.xx:3306/redis?useUnicode=true&characterEncoding=UTF-8
    username: xxx           # 需要修改填写
    password: xxxxx         # 需要修改填写
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    minIdle: 5
    maxActive: 100
    initialSize: 10
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 50
    removeAbandoned: true
    filters: stat # ,wall,log4j # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    useGlobalDataSourceStat: true # 合并多个DruidDataSource的监控数据
    druidLoginName: gcx # 登录druid的账号
    druidPassword: gcx # 登录druid的密码
    cachePrepStmts: true  # 开启二级缓存
mybatis:
  typeAliasesPackage: com.gcxzflgl.redis.mapper      # 需要修改填写
  mapperLocations: classpath:/mapper/*.xml
  mapperScanPackage: com.gcxzflgl.redis.mapper
  configLocation: classpath:/mybatis-config.xml

3.再resources下新建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration  
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
     "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<settings>
	    <!-- 使全局的映射器启用或禁用缓存。 -->
		<setting name="cacheEnabled" value="true" />
		<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
		<setting name="lazyLoadingEnabled" value="true" />
		<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->        
         <setting name="aggressiveLazyLoading" value="true"/>        
         <!-- 是否允许单条sql 返回多个数据集  (取决于驱动的兼容性) default:true -->
		<setting name="multipleResultSetsEnabled" value="true" />
		<!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
		<setting name="useColumnLabel" value="true" />
		<!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  default:false  -->
		<setting name="useGeneratedKeys" value="false" />
		<!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分  FULL:全部  -->
		<setting name="autoMappingBehavior" value="PARTIAL" />
		<!-- 这是默认的执行类型  (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)  -->
		<setting name="defaultExecutorType" value="SIMPLE" />
		
		<setting name="defaultStatementTimeout" value="25" />
		
		<setting name="defaultFetchSize" value="100" />
		
		<setting name="safeRowBoundsEnabled" value="false" />
		<!-- 使用驼峰命名法转换字段。 -->
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<!-- 设置本地缓存范围 session:就会有数据的共享  statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
		<setting name="localCacheScope" value="SESSION" />
		<!-- 默认为OTHER,为了解决oracle插入null报错的问题要设置为NULL -->
		<setting name="jdbcTypeForNull" value="NULL" />
		<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
	</settings>
	
</configuration>


4.再config包下创建DataSourceConfig.java配置文件注入sql相关

package com.gcxzflgl.redis.config;




/**
 * Created by wanlichao on 2016/10/25 0025.
 */

@Configuration
@MapperScan("com.gcxzflgl.redis.mapper")
public class DataSourceConfig {
    private Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);

    @Value("${spring.datasource.url}")
    private String dbUrl;

    @Value("${spring.datasource.type}")
    private String dbType;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.initialSize}")
    private int initialSize;

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

    @Value("${spring.datasource.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;

    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;

    @Value("${spring.datasource.filters}")
    private String filters;

    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;

    @Value("${spring.datasource.useGlobalDataSourceStat}")
    private boolean useGlobalDataSourceStat;

    @Value("${spring.datasource.druidLoginName}")
    private String druidLoginName;

    @Value("${spring.datasource.druidPassword}")
    private String druidPassword;



    @Bean(name="dataSource")
    @Primary //不要漏了这
    public DataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
        try {
            datasource.setUrl(this.dbUrl);
            datasource.setDbType(dbType);
            datasource.setUsername(username);
            datasource.setPassword(password);
            datasource.setDriverClassName(driverClassName);
            datasource.setInitialSize(initialSize);
            datasource.setMinIdle(minIdle);
            datasource.setMaxActive(maxActive);
            datasource.setMaxWait(maxWait);
            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            datasource.setValidationQuery(validationQuery);
            datasource.setTestWhileIdle(testWhileIdle);
            datasource.setTestOnBorrow(testOnBorrow);
            datasource.setTestOnReturn(testOnReturn);
            datasource.setPoolPreparedStatements(poolPreparedStatements);
            datasource.setFilters(filters);
        } catch (SQLException e) {
            logger.error("druid configuration initialization filter", e);
        }
        return datasource;
    }

    /  下面是druid 监控访问的设置  /
    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");  //url 匹配
        reg.addInitParameter("allow", "192.168.16.110,127.0.0.1"); // IP白名单 (没有配置或者为空,则允许所有访问)
        reg.addInitParameter("deny", "192.168.16.111"); //IP黑名单 (存在共同时,deny优先于allow)
        reg.addInitParameter("loginUsername", this.druidLoginName);//登录名
        reg.addInitParameter("loginPassword", this.druidPassword);//登录密码
        reg.addInitParameter("resetEnable", "false"); // 禁用HTML页面上的“Reset All”功能
        return reg;
    }

    @Bean(name="druidWebStatFilter")
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); //忽略资源
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
        filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
        return filterRegistrationBean;
    }
}

5.创建sql脚本

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `sys_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', '高晨曦');
INSERT INTO `sys_user` VALUES ('2', '瑞燊儿');

6.再domain包下新建实体

package com.gcxzflgl.redis.domain;

import java.io.Serializable;

public class User implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = -4415438719697624729L;


    private String id;

    private String userName;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }


    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

7.再mapper包中创建mapper映射类

package com.gcxzflgl.redis.mapper;

import com.gcxzflgl.redis.domain.User;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Component;

import java.util.List;

@Mapper
@Component
public interface UserMapper {

	@Insert("insert sys_user(id,user_name) values(#{id},#{userName})")
	void insert(User u);
	
	@Update("update sys_user set user_name = #{userName} where id=#{id} ")
	void update(User u);
	
	@Delete("delete from sys_user where id=#{id} ")
	void delete(@Param("id") String id);

	@Select("select id,user_name from sys_user where id=#{id} ")
	User find(@Param("id") String id);

	//注:方法名和要UserMapper.xml中的id一致
	List<User> query(@Param("userName") String userName);

	@Delete("delete from sys_user")
	void deleteAll();
}

对应的resource/mapper下创建UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.gcxzflgl.redis.mapper.UserMapper">
 
<select id="query"  resultType="com.gcxzflgl.redis.domain.User">
    select id ,user_name 
    from sys_user 
    where 1=1
    <if test="userName != null">
      and user_name like CONCAT('%',#{userName},'%')
    </if>
</select>
</mapper>

8.再service层引入业务方法类UserService

package com.gcxzflgl.redis.biz;


/**
 * @author gcxzf$
 * @version : UserService$, v 0.1 2020/6/13$ 15:16$ gcxzf$ Exp$
 */
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;
 

    /**
     * 查找user
     * @param id
     * @return
     */
    public User find(String id){     
        User users = userMapper.find(id); 
        return users;  
    }
}

9.再rest报下创建UserController

package com.gcxzflgl.redis.rest;


/**
 * @author gcxzf$
 * @version : UserController$, v 0.1 2020/6/13$ 15:12$ gcxzf$ Exp$
 */

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 查找指定user
     * @param id
     * @return
     */
    @GetMapping("/find")
    public User find(@RequestParam(value = "id",required = true) String id){
        return userService.find(id);
    }
}

10.启动项目访问:http://xxx.xxx.xx.xx:8080/find?id=1
在这里插入图片描述

Springboot与Cache整合使用

SpringCache 常用注解

@Cacheable(查)来划分可缓存的方法 - 即,结果存储在缓存中的方法,以便在后续调用(具有相同的参数)时,返回缓存中的值而不必实际执行该方法
@CachePut(修改、增加)当需要更新缓存而不干扰方法执行时,可以使用@CachePut注释。也就是说,始终执行该方法并将其结果放入缓存中(根据@CachePut选项)
@CacheEvict(删除) :对于从缓存中删除陈旧或未使用的数据非常有用,指示缓存范围内的驱逐是否需要执行而不仅仅是一个条目驱逐

改造现有代码:

1.再pom.xml引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

2.再启动类RedisApplication.java中开启cache缓存注解@EnableCaching

package com.gcxzflgl.redis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class RedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }

}

3.改造userservice类
首先再UserService类上添加注解 @CacheConfig(cacheNames = “userCache”) 此类的cache缓存名称统一userCache开头
再find方法中添加注解 @Cacheable(key = “#p0”,unless = “#result == null”) key = "#p0"代表缓存的key格式:userCache::id 作为缓存key,unless 代表如果查询结果返回null不进行缓存
完整代码如下:

package com.gcxzflgl.redis.biz;



/**
 * @author gcxzf$
 * @version : UserService$, v 0.1 2020/6/13$ 15:16$ gcxzf$ Exp$
 */
@Service
@CacheConfig(cacheNames = "userCache")
public class UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 查找user
     * @param id
     * @return
     */
    @Cacheable(key = "#p0",unless = "#result == null")
    public User find(String id){
        User user = userMapper.find(id);
        System.out.println("缓存中不存在user");
        return user;
    }
}

4.重启项目测试,查看缓存是否存在
访问地址:http://xxx.xxx.xx.xx:8080/find?id=1
在这里插入图片描述
5.其余缓存注解大同小异,本文不再演示

Redis作为mybatis二级缓存

先引申一个问题:springboot cache 存在什么问题,
第一,生成key过于简单,容易冲突userCache::1
第二,无法设置过期时间,默认过期时间为永久不过期
第三,配置序列化方式,默认的是序列化JDKSerialazable

为了解决这个问题,我们再次改造工程代码

1.自定义KeyGenerator,本文采用(类名+方法名做唯一性区分)
2.自定义cacheManager,设置缓存过期时间
3.自定义序列化方式,Jackson
再RedisConfig中配置如下代码:

1.再config包下RedisCofig.java新增方法

/**
     * 使用类名+方法名作为缓存key
     * @return
     */
    @Bean
    public KeyGenerator simpleKeyGenerator() {
        return (o, method, objects) -> {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(o.getClass().getSimpleName());
            stringBuilder.append(".");
            stringBuilder.append(method.getName());
            stringBuilder.append("[");
            for (Object obj : objects) {
                stringBuilder.append(obj.toString());
            }
            stringBuilder.append("]");

            return stringBuilder.toString();
        };
    }

    /**
     * 设置cache缓存过期时间
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return new RedisCacheManager(
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                this.getRedisCacheConfigurationWithTtl(600), // 默认策略,未配置的 key 会使用这个
                this.getRedisCacheConfigurationMap() // 指定 key 策略
        );
    }

    /**
     * 给指定类型的key设置过期时间
     * @return
     */
    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
        //指定cache头名称为UserInfoList的方法缓存过期时间为100s
        redisCacheConfigurationMap.put("UserInfoList", this.getRedisCacheConfigurationWithTtl(100));
         //指定cache头名称为UserInfoListAnother的方法缓存过期时间为100s
        redisCacheConfigurationMap.put("UserInfoListAnother", this.getRedisCacheConfigurationWithTtl(18000));

        return redisCacheConfigurationMap;
    }

	/**
     * 设置过期时间,并指定序列化方式为Jackson
     * @param seconds
     * @return
     */
    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
                RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(jackson2JsonRedisSerializer)
        ).entryTtl(Duration.ofSeconds(seconds));

        return redisCacheConfiguration;
    }
    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
                RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(jackson2JsonRedisSerializer)
        ).entryTtl(Duration.ofSeconds(seconds));

        return redisCacheConfiguration;
    }

2.配置以上策略后,需要再UserService类中的find方法上指定缓存策略改造如下:

package com.gcxzflgl.redis.biz;

import com.gcxzflgl.redis.domain.User;
import com.gcxzflgl.redis.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;


/**
 * @author gcxzf$
 * @version : UserService$, v 0.1 2020/6/13$ 15:16$ gcxzf$ Exp$
 */
@Service
@CacheConfig(cacheNames = "userCache")
public class UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 查找user
     * @param id
     * @return
     */
//    @Cacheable(key = "#p0",unless = "#result == null")
    @Cacheable(value = "UserInfoList", keyGenerator = "simpleKeyGenerator") // @Cacheable 会先查询缓存,如果缓存中存在,则不执行方法
    public User find(String id){
        User user = userMapper.find(id);
        System.out.println("缓存中不存在user");
        return user;
    }
}

3.再次重启项目测试验证方法
访问地址:http://xxx.xxx.xx.xx:8080/find?id=1
在这里插入图片描述

4.测试验证redis缓存和数据库进行对比
准备条件:
1)再userservice中复制一个find方法不配置注解,只是方便演示,controller同理:

/**
     * 查找user(noCache)
     * @param id
     * @return
     */
    public User findNoCache(String id){
        User user = userMapper.find(id);
        return user;
    }
  /**
     * 查找user(noCache)
     * @param id
     * @return
     */
    @GetMapping("/findNoCache")
    public User findNoCache(@RequestParam(value = "id",required = true) String id){
        return userService.findNoCache(id);
    }

)2.Linux上安装测试工具 apache abtest

abtest的安装
1)yum install -y httpd-tools
2)ab -V检验是否安装成功

验证地址:
ab -n1000 -c10 http://xxx.xxx.xx.xx:8080/findNoCache?id=2
ab -n1000 -c10 http://xxx.xx.xx.xx:8080/find?id=2

参数说明:
1)-n:进行http请求的总个数
2)-c:请求的client个数,也就是请求并发数
3) 统计qps:qps即每秒并发数,request per second

测试案例:

10个并发情况下1000请求执行参数(没用缓存)

[root@redis-master src]# ab -n1000 -c10 http://192.168.124.3:8080/findNoCache?id=2
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.124.3 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        
Server Hostname:        192.168.124.3
Server Port:            8080

Document Path:          /findNoCache?id=2
Document Length:        33 bytes

Concurrency Level:      10
Time taken for tests:   8.282 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      138000 bytes
HTML transferred:       33000 bytes
Requests per second:    120.75 [#/sec] (mean) (qps结果)
Time per request:       82.819 [ms] (mean)
Time per request:       8.282 [ms] (mean, across all concurrent requests)
Transfer rate:          16.27 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   75 700.0      1    7018
Processing:     1    3   2.8      3      40
Waiting:        0    3   2.8      3      39
Total:          2   78 700.0      4    7022

Percentage of the requests served within a certain time (ms)
  50%      4
  66%      5
  75%      6
  80%      6
  90%      7
  95%      8
  98%     20
  99%   7016
 100%   7022 (longest request)

10个并发情况下1000请求执行参数(使用缓存)

[root@redis-master src]# ab -n1000 -c10 http://192.168.124.3:8080/find?id=2
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.124.3 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        
Server Hostname:        192.168.124.3
Server Port:            8080

Document Path:          /find?id=2
Document Length:        33 bytes

Concurrency Level:      10
Time taken for tests:   1.565 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      138000 bytes
HTML transferred:       33000 bytes
Requests per second:    638.99 [#/sec] (mean) (qps结果)
Time per request:       15.650 [ms] (mean)
Time per request:       1.565 [ms] (mean, across all concurrent requests)
Transfer rate:          86.11 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    7  70.6      2    1003
Processing:     1    3   1.0      3       9
Waiting:        1    3   0.9      3       8
Total:          1   10  70.5      5    1005

Percentage of the requests served within a certain time (ms)
  50%      5
  66%      5
  75%      6
  80%      6
  90%      6
  95%      7
  98%      8
  99%     10
 100%   1005 (longest request)

其他测试条件:

10个并发的情况下 1000请求redis qps:963.85[#/sec] (mean) DB qps: 766.75 [#/sec] (mean)
100个并发的情况下 1000请求redis qps:1130.60 [#/sec] (mean) DB qps:956.15 [#/sec] (mean)
100个并发的情况下10000请求redsi qps: 2102.39 [#/sec] (mean) DB qps: 679.07 [#/sec] (mean)
500个并发的情况下 10000请求redis qps:374.91 [#/sec] (mean) DB qps:扛不住

Redis分布式session共享

1、cookie与session
1) Cookie是什么? Cookie 是一小段文本信息,伴随着用户请求和页面在 Web 服务器和浏览器之间传递。Cookie 包含每次用户访问站点时 Web 应用程序都可以读取的信息,我们可以看到在服务器写的cookie,会通过响应头Set-Cookie的方式写入到浏览器

2)HTTP协议是无状态的,并非TCP一样进行三次握手,对于一个浏览器发出的多次请求,WEB服务器无法区分是不是来源于同一个浏览器。所以服务器为了区分这个过程会通过一个
sessionid来区分请求,而这个sessionid是怎么发送给服务端的呢。cookie相对用户是不可见的,用来保存这个sessionid是最好不过了

1.再pom.xml引入依赖

 <dependency>
     <groupId>org.springframework.session</groupId>
     <artifactId>spring-session-data-redis</artifactId>
 </dependency>

2.再RedisConfig.java类上添加注解,指定过期时间50s

@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 50)

3.再rest包下新增SessionController,重启工程测试

package com.gcxzflgl.redis.rest;

@RestController
public class SessionController {

    @RequestMapping(value = "/setSession", method = RequestMethod.GET)
    public Map<String, Object> setSession (HttpServletRequest request){
        Map<String, Object> map = new HashMap<>();
        request.getSession().setAttribute("request Url", request.getRequestURL());
        map.put("request Url", request.getRequestURL());
        return map;
    }

    @RequestMapping(value = "/getSession", method = RequestMethod.GET)
    public Object getSession (HttpServletRequest request){
        Map<String, Object> map = new HashMap<>();
        map.put("sessionIdUrl",request.getSession().getAttribute("request Url"));
        map.put("sessionId", request.getSession().getId());
        return map;
    }
}

3 .用谷歌和火狐浏览器进行验证
谷歌在这里插入图片描述
火狐
在这里插入图片描述
查看结果 (再次刷新session时间从新累计50s进行倒计时)
在这里插入图片描述

至此,基本的使用讲解列举完毕!

下章更新Redis实时排行榜!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值