一、项目介绍(本项目用的编程语言是jdk8,项目源码: https://github.com/zhzhair/mybatis-druid-spring-boot.git)
  1.引入pom依赖:
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.14</version>
    </dependency>
  </dependencies>
  由引入的jar包可知,项目用MySQL + mybatis + redis架构,数据库连接池用阿里的druid

  2.配置文件application.yml配置(配置MySQL数据源、druid连接池及监控、redis):
  spring:
    datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false"
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      max-active: 100
      min-idle: 10
      max-wait: 60000
      filter:
        stat:
          merge-sql: true
          slow-sql-millis: 200
      test-on-borrow: true
      validation-query: SELECT 1
      use-global-data-source-stat: true
      # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      # http://127.0.0.1:8080/druid2/index.html
      filters: stat,wall,slf4j
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
    redis:
      host: 127.0.0.1
      password:
      database: 0
      timeout: PT1M1S
      jedis:
        pool.max-active: 200
        pool.max-idle: 50
        pool.max-wait: PT-1S
        pool.min-idle: 10

  table-num: 64

  3.引入druid配置类(sql和uri监控访问地址:http://localhost:8080/druid/index.html,用户名和密码分别是admin和123456):

    package com.example.demo.config.druid;

    import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class DruidConfiguration {
@Bean
public ServletRegistrationBean DruidStatViewServle2() {
//org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid2/*");
//添加初始化参数:initParams
servletRegistrationBean.addUrlMappings("/druid/*");
//白名单:
// servletRegistrationBean.addInitParameter("allow","192.168.1.106");
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
// servletRegistrationBean.addInitParameter("deny", "192.168.1.73");
//登录查看信息的账号密码.
servletRegistrationBean.addInitParameter("loginUsername","admin");
servletRegistrationBean.addInitParameter("loginPassword","123456");
//是否能够重置数据.
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
} @Bean
public FilterRegistrationBean druidStatFilter2(){
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(new WebStatFilter());
filterRegistrationBean.setName("druidFilter2");
//添加过滤规则.
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息.
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*");
return filterRegistrationBean;
} }

  4.在测试类创建表user_*和user_mobile_*:

    @RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests { @Resource
private TestUserService userService;
@Test
public void contextLoads() {
userService.dropTables();
userService.createTables();
} } @Service
public class TestUserServiceImpl implements TestUserService {
@Resource
private UserMapper userMapper;//jdbc操作接口
@Value("${table-num}")
private int tableNum;//分表的个数 @Override
public void dropTables() {
IntStream.range(0,tableNum).parallel().forEach(this::dropTables);
} private void dropTables(int i){
userMapper.dropTable("user_" + i);
userMapper.dropTable("user_mobile_" + i);
} @Override
public void createTables() {
IntStream.range(0,tableNum).parallel().forEach(this::createTables);
} private void createTables(int i){
String suffix = String.valueOf(i);
userMapper.createTableUser(suffix);
userMapper.createTableUserMobile(suffix);
}
}

  5.编写restful风格的接口(包括登录和注册):

    @RestController
@RequestMapping("test/user")
public class TestUserController extends BaseController {
@Resource
private TestUserService userService;
@Resource
private TokenManager tokenManager;//给登录用户生成token,并放到redis
@RequestMapping(value = "/loginByMobile", method = {RequestMethod.GET}, produces = {MediaType.APPLICATION_JSON_VALUE})
public BaseResponse<LoginResponse> loginByMobile() {
BaseResponse<LoginResponse> baseResponse = new BaseResponse<>();
Integer userId = userService.getUserIdByMobile();
if(userId != null){
baseResponse.setCode(0);
baseResponse.setMsg("手机号登录成功");
String token = tokenManager.generateToken(userId);
LoginResponse loginResponse = new LoginResponse();
loginResponse.setUserId(userId);
loginResponse.setToken(token);
loginResponse.setExpire(System.currentTimeMillis() + 3600 * 1000);
baseResponse.setData(loginResponse);
}else{
baseResponse.setCode(-3);
baseResponse.setMsg("手机号未注册");
}
return baseResponse;
} @RequestMapping(value = "/register", method = {RequestMethod.POST}, produces = {MediaType.APPLICATION_JSON_VALUE})
public BaseResponse<User> register() {
BaseResponse<User> baseResponse = new BaseResponse<>();
Integer userId = userService.getUserIdByMobile();
if(userId == null){
User user = userService.register();
baseResponse.setCode(0);
baseResponse.setData(user);
baseResponse.setMsg("注册成功");
}else{
baseResponse.setCode(1);
baseResponse.setMsg("手机号已被注册");
}
return baseResponse;
}
} @Service
public class TestUserServiceImpl implements TestUserService {
@Resource
private UserService userService;
@Value("${table-num}")
private int tableNum;//分表的个数 @Override
public Integer getUserIdByMobile() {
return userService.getUserIdByMobile(getMobileStr());
} @Override
public User register() {
UserRequest userRequest = new UserRequest();
userRequest.setMobile(getMobileStr());
userRequest.setIcon("http://127.0.0.1/"+getMobileStr()+".jpg");
int rand = new Random().nextInt(4);
userRequest.setNickname(new String[]{"xiaoming","xiaohong","xiaoqiang","xiaoli"}[rand]);
return userService.register(userRequest);
} /**
* 模拟手机号
*/
private String getMobileStr(){
String[] strings = {"13","15","16","18"};
String beginString = strings[new Random().nextInt(4)];
int a = new Random().nextInt(10_0000_0000);
String endString = String.valueOf(a);
int length = 9 - endString.length();
StringBuilder stringBuilder = new StringBuilder(beginString);
for (int i = 0; i < length; i++) {
stringBuilder.append("0");
}
return stringBuilder.append(endString).toString();
}
} @Service
public class UserServiceImpl implements UserService {
private final String USER_ID_INC = "USER_ID_INC";
@Resource
private UserMapper userMapper;//jdbc操作接口
@Resource(name = "stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate; @Value("${table-num}")
private int tableNum;//分表的个数 @Transactional(isolation = Isolation.REPEATABLE_READ)
@Override
public User register(UserRequest userRequest) {
String usercode = redisTemplate.opsForValue().get(USER_ID_INC);
Integer userId;
if(usercode == null){//如果redis的数据丢失,就找出最大的userId,并给USER_ID_INC赋值
int temp = 0;
for (int i = 0; i < tableNum; i++) {
Integer maxUserId = userMapper.getMaxUserId(String.valueOf(i));
if(maxUserId != null && temp < maxUserId){
temp = maxUserId;
}
}
userId = temp + 1;
redisTemplate.opsForValue().set(USER_ID_INC,String.valueOf(userId));
}else{
Long num = redisTemplate.opsForValue().increment(USER_ID_INC,1);
userId = Integer.valueOf(num + "");
}
User user = new User();
user.setUserId(userId);
user.setMobile(userRequest.getMobile());
user.setIcon(userRequest.getIcon());
user.setNickname(userRequest.getNickname());
int rem = userId % tableNum;
userMapper.insertUser(user,String.valueOf(rem));
int rem0 = Math.abs(userRequest.getMobile().hashCode()) % tableNum;
String mobile = userRequest.getMobile();
userMapper.insertUserMobile(mobile,userId,String.valueOf(rem0));
return user;
} @Override
public Integer getUserIdByMobile(String mobile) {
int rem = Math.abs(mobile.hashCode()) % tableNum;
return userMapper.getUserByMobile(mobile,String.valueOf(rem));
} }

二、用jmeter做并发测试(jmeter版本4.0):
  1.双击打开bin目录下的jmeter.bat文件,菜单选简体中文:Options->Choose language->Chinese(Simplified)。点文件夹图标可以选择已有的jmeter脚本。

  2.右键测试计划->添加->Threads(Users)->线程组,然后配置执行线程数、持续时间等信息。登录和注册我都建了单独的线程组,其中:登录的线程数36000,持续时间600秒;注册的线程数6000,持续时间600秒。
  3.右键测试计划->添加->监听器->(查看结果数和聚合报告等,用于分析并发测试结果)。
  4.分别右键选中登录和注册的线程组->添加->sampler->HTTP请求,配置如下:
登录和注册的协议都填http,IP都填127.0.0.1,端口号都填8080。登录的方式选GET,注册的方式选POST。登录的路径填/test/user/loginByMobile,注册的路径填/test/user/register。
  5.点击打开聚合报告,启动项目,点击菜单栏绿色的三角形图标运行,观察聚合报告的结果如下图所示:

三、查看druid的sql监控和uri监控:
  jmeter运行时,访问http://localhost:8080/druid/index.html,sql监控和webUI等监控结果如图所示:

spring boot2.0.4集成druid,用jmeter并发测试工具调用接口,druid查看监控的结果的更多相关文章

  1. 【spring cloud】spring cloud2.X spring boot2.0.4调用feign配置Hystrix Dashboard 和 集成Turbine 【解决:Hystrix仪表盘Unable to connect to Command Metric Stream】【解决:Hystrix仪表盘Loading...】

    环境: <java.version>1.8</java.version><spring-boot.version>2.0.4.RELEASE</spring- ...

  2. Spring Boot2.0使用Spring Security

     一.Spring Secutity简介     Spring 是一个非常流行和成功的 Java 应用开发框架.Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性 ...

  3. spring boot 2.0(一)权威发布spring boot2.0

    Spring Boot2.0.0.RELEASE正式发布,在发布Spring Boot2.0的时候还出现一个小插曲,将Spring Boot2.0同步到Maven仓库的时候出现了错误,然后Spring ...

  4. Spring Boot2.0之整合事物管理

    首先Spring 事务分类 1.声明事务  原理:基于编程事务的 2.编程事务  指定范围 扫包去解决 3.事务原理:AOP技术   通过环绕通知进行了拦截 使用Spring 事务注意事项: 不要tr ...

  5. 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构

    github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...

  6. Spring Boot2.0 设置拦截器

    所有功能完成 配置登录认证 配置拦截器 在spring boot2.0 之后 通过继承这个WebMvcConfigurer类 就可以完成拦截 新建包com.example.interceptor; 创 ...

  7. Spring Boot2.0 静态资源被拦截问题

    在Spring Boot2.0+的版本中,只要用户自定义了拦截器,则静态资源会被拦截.但是在spring1.0+的版本中,是不会拦截静态资源的. 因此,在使用Spring Boot2.0+时,配置拦截 ...

  8. spring boot2.0(一 ) 基础环境搭建

    1.基础配置 开发环境:window jdk版本:1.8(spring boot2.0最低要求1.8) 开发工具:eclipse 构建方式:maven3 2.POM配置文件 <project x ...

  9. Spring Boot2.0 整合 Kafka

    Kafka 概述 Apache Kafka 是一个分布式流处理平台,用于构建实时的数据管道和流式的应用.它可以让你发布和订阅流式的记录,可以储存流式的记录,并且有较好的容错性,可以在流式记录产生时就进 ...

随机推荐

  1. wget在linux中安装出现错误解决办法

    在使用wget命令报错 certificate common name 'xxx' doesn't match requestde host name,我们一般的解决办法是查找下载地址,但是有时候更换 ...

  2. JSP中常用的的EL表达式的汇总

    Jsp基础知识 jsp的组成 html静态页面(css.javascript) java代码 <% %> (_jspService方法中) 内置对象 out request 表达式 < ...

  3. H(X|Y)的推到过程

  4. vue学习初探

    一.环境的搭建安装 VS Code vue开发环境的搭建 理解vue的脚手架 合适的cnpm版本

  5. python_while

    while 格式 while 条件 : pass 使用 while True : print("精忠报国") print("粉红的回忆") print(&quo ...

  6. 在自己写的C#类中调用 ASP.NET的Request,server 等对象

    加命名空间(可能需要在项目中先加引用,再在类中如下引用) using System.Web.SessionState; HttpContext.Current.Session["TotalP ...

  7. 2016湖南省赛 [Cloned]

    A.2016 给出正整数 n 和 m,统计满足以下条件的正整数对 (a,b) 的数量: 1. 1≤a≤n,1≤b≤m; 2. a×b 是 2016 的倍数. Input   输入包含不超过 30 组数 ...

  8. Spring Cloud Netflix vs Spring Cloud Alibaba

    Spring Cloud Netflixhttps://spring.io/projects/spring-cloud-netflix spring-cloud-alibaba/README-zh.m ...

  9. Java8新特性(一)_interface中的static方法和default方法

    什么要单独写个Java8新特性,一个原因是我目前所在的公司用的是jdk8,并且框架中用了大量的Java8的新特性,如上篇文章写到的stream方法进行过滤map集合.stream方法就是接口Colle ...

  10. git总结三、关于分支下——团队合作中最重要的合并分支

    合并分支是团队合作开发中常见的操作,这里涉及到两个命令:git merge 和 git rebase 下面来好好说一下git merge和git rebase都是怎样工作的 一. 1.新建一个空目录并 ...