目录
- Springboot项目创建
- Springboot与Redis整合
- Springboot与Mybatis整合
- Springboot与Cache整合使用
- Redis作为mybatis二级缓存
- 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实时排行榜!