一、项目介绍(本项目用的编程语言是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. 基于Metronic的Bootstrap开发框架--资产编码打印处理

    在开发业务管理系统的时候,往往涉及到资产信息及编码的打印处理,如我们需要对资产信息.条形码.二维码一起打印,以便贴在具体资产信息上面,方便微信公众号.企业微信进行业务处理,那么编码的打印就很有必要了, ...

  2. 特殊需求:EF 6.x如何比较TimeSpan格式的字符串?EF Core实现方式是否和EF 6.x等同?

    前言 我们知道C#中的TimeSpan对应SQL Server数据库中的Time类型,但是如果因为特殊需求数据库存储的不是Time类型,而是作为字符串,那么我们如何在查询数据时对数据库所存储的字符串类 ...

  3. nginx安装,启动亲测有效

    一:安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c++ libtool  openssl openssl-devel 二:安装PCRE,让 N ...

  4. 如何使用django操作数据库,向原有表中添加新的字段信息并建立一个多对多的关系?

    (注:本人用的pycharm开发工具) 1.在你要添加新字段的app的 models.py 文件中添加需要新增的字段(book表新增authors字段并和author建立多对多关系,author表新增 ...

  5. 配置spring的监听器 让spring随项目的启动而启动

    <!-- 配置spring的监听器 让spring随项目的启动而启动 --> <listener> <listener-class>org.springframew ...

  6. gulp 入门使用

      gulp 入门使用 使用场景 相信大家在传统的开发模式下 都是 html + css + js 然后静态文件不经过任何处理 部署到服务器,这样会有很多漏洞例如: 1.在网站上查看F12 就可以看到 ...

  7. drf相关问题

    drf自定义用户认证: 登录默认 使用django的ModelBackend,对用户名和密码进行验证.但我们平时登录网站时除了用户名也可以用邮箱或手机进行登录,这就需要我们自己扩展backend 一. ...

  8. Nuget 多平台多目标快速自动打包

    构建现代的 .Net 应用离不开 Nuget 的支持,而快速打包 Nuget 成了提高生产率的有效方法. 1. 前置条件 为了实现 Nuget 的快速打包,我们需要先解决一些前置依赖,无论是 .Net ...

  9. js 调用打印机方法

    <button onclick="localdy({php echo $item['order']['id'];})" class="btn btn-xs orde ...

  10. openflow packet_out和packet_in分析

    任务目的 1. 掌握OpenFlow交换机发送Packet-in消息过程及其消息格式. 2. 掌握OpenFlow控制器发送Packet-out消息过程及其消息格式. 实验原理 Packet-In 使 ...