IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 记录一下Java程序卡住的问题(长时间无返回无响应) -> 正文阅读

[Java知识库]记录一下Java程序卡住的问题(长时间无返回无响应)

作者:token annotation punctuation

一、jstack 查看运行情况,如图

jstack是java虚拟机自带的一种堆栈跟踪工具。
11666是java 进程 pid

jstack -l 11666

在这里插入图片描述

排查发现数据库连接池出现问题了

at com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:1518)
	at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1143)
	at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1014)
	at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:994)
	at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:984)
	at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:103)

二、利用druid监控或者 jconsole 查看连接池的状态

需要配置application.yml或者写组件

1.druid监控配置

datasource:
    druid:
      stat-view-servlet:
        enabled: true
        loginUsername: admin
        loginPassword: 123456
        allow:
      web-stat-filter:
        enabled: true
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;


/**
 * @descriptions:
 * @author: LZH
 * @date: 2022/5/16/016 14:37
 * @version: 1.0
 */
@Configuration
public class DruidConfig {
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid() {
        return new DruidDataSource();
    }

    /* 配置一个Druid监控
         1.配置一个druid的后台  管理servlet
         2.配置一个druid的filter
      */
//  1.配置一个druid的后台  管理servlet
    @Bean
    public ServletRegistrationBean statViewServlet() {
//        注意:请求是/druid/*
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        Map<String, String> initParam = new HashMap<>();
        initParam.put(StatViewServlet.PARAM_NAME_USERNAME, "admin");
        initParam.put(StatViewServlet.PARAM_NAME_PASSWORD, "123456");
//        如果不写,则默认所有ip都可以访问
        initParam.put(StatViewServlet.PARAM_NAME_ALLOW, "");
        initParam.put(StatViewServlet.PARAM_NAME_DENY, "192.168.10.11");
        bean.setInitParameters(initParam);
        return bean;
    }

    //     2.配置一个druid的filter
    @Bean
    public FilterRegistrationBean webStatFilter() {
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new WebStatFilter());

        Map<String, String> initParams = new HashMap<>();
        initParams.put(WebStatFilter.PARAM_NAME_EXCLUSIONS, "*.js,*.css,/druid/*");
        bean.setInitParameters(initParams);
//        设置拦截请求
        bean.setUrlPatterns(Arrays.asList("/*"));
        return bean;
    }

}

在这里插入图片描述

2.jconsole

找到java安装目录,如 C:\Program Files\Java\jdk-11.0.6\bin

在这里插入图片描述
打开后选择已经运行的java程序找到MBean

在这里插入图片描述

三、配置连接数大小以及等待时间

1. DataSourceAutoConfiguration

由于系统原因,已经默认有了 DataSourceExtraProperties相关的配置我们对此重新覆盖了一下


package xxx;

import com.alibaba.druid.pool.DruidDataSource;
import xxx.QueryInterceptor;
import xxx.SaveInterceptor;
import xxx.DynamicDataSource;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.*;

@EnableConfigurationProperties({DataSourceExtraProperties.class})
@Configuration
public class DataSourceAutoConfiguration {
    public DataSourceAutoConfiguration() {
    }

    @Primary
    @ConditionalOnClass({DruidDataSource.class})
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean(
            initMethod = "init",
            destroyMethod = "close"
    )
/*
    public DruidDataSource dataSourceDefault(DataSourceProperties dataSourceProperties) {
        return (DruidDataSource)dataSourceProperties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
    }

*/
    public DruidDataSource dataSourceDefault() {
        return new DruidDataSource();
    }

    @Bean
    public DynamicDataSource dataSource(DataSourceExtraProperties dataSourceExtraProperties, DataSource dataSourceDefault) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap(1);
        targetDataSources.put("dataSourceDefault", dataSourceDefault);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultDbtype(dataSourceExtraProperties.getDbType());
        return dynamicDataSource;
    }

    @Bean(
            name = {"jdbcTemplate"}
    )
    public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    public PageInterceptor pageInterceptor() {
        PageInterceptor pageInterceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("autoRuntimeDialect", "true");
        properties.setProperty("rowBoundsWithCount", "true");
        pageInterceptor.setProperties(properties);
        return pageInterceptor;
    }

    @Bean
    public QueryInterceptor queryInterceptor() {
        return new QueryInterceptor();
    }

    @Bean
    public SaveInterceptor saveInterceptor() {
        return new SaveInterceptor();
    }

    @Bean(
            name = {"abSqlSessionFactory"}
    )
    public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource, SaveInterceptor saveInterceptor) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(this.resolveMapperLocations("classpath*:com/xx/*/mapping/*.xml", "classpath*:com/xx/*/*/mapping/*.xml"));
        sqlSessionFactoryBean.setPlugins(new Interceptor[]{this.pageInterceptor(), this.queryInterceptor(), saveInterceptor});
        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties mysqlp = new Properties();
        mysqlp.setProperty("MySQL", "mysql");
        mysqlp.setProperty("Oracle", "oracle");
        databaseIdProvider.setProperties(mysqlp);
        sqlSessionFactoryBean.setDatabaseIdProvider(databaseIdProvider);
        return sqlSessionFactoryBean;
    }

    private Resource[] resolveMapperLocations(String... locations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList();
        String[] var4 = locations;
        int var5 = locations.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String mapperLocation = var4[var6];

            try {
                Resource[] mappers = resourceResolver.getResources(mapperLocation);
                resources.addAll(Arrays.asList(mappers));
            } catch (IOException var9) {
            }
        }

        return (Resource[])resources.toArray(new Resource[resources.size()]);
    }

    @Bean({"abMapperScannerConfigurer"})
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("abSqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.xx.**.dao");
        return mapperScannerConfigurer;
    }

    @Bean({"abSqlSessionTemplate"})
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("abSqlSessionFactory") SqlSessionFactoryBean sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory.getObject());
    }
}

2. application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: xxx
    username: xx
    password: xx
    dbType: mysql
    initial-size: 10
    min-idle: 10
    max-active: 50
    # 配置获取连接等待超时的时间
    max-wait: 6000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    timeBetweenEvictionRunsMillis: 60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    # 打开PSCache,并且指定每个连接上PSCache的大小
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20

总结

1.我们先利用 jstack 排查问题找出是:
数据库连接池的连接长时间没有释放,导致后续的请求过来了但是查询数据库的连接还在等待导致系统卡死的问题

2.利用 vconsole 的监控去配置 datasource 的属性发现一直不生效,开始寻找解决方案,参考如下
springboot配置druid数据源不生效问题

3.由于出现上述问题多半是并发造成的,我们对此进行模拟并发请求测试是否真正解决问题

进入你的网页程序f12打开找到network找一个后台请求,最好是数据量大一点的,如图
在这里插入图片描述
linux中 vi a.sh把复制的东西粘贴

curl 'https://position.csdnimg.cn/oapi/get' \
  -H 'authority: position.csdnimg.cn' \
  -H 'pragma: no-cache' \
  -H 'cache-control: no-cache' \
  -H 'sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"' \
  -H 'accept: application/json, text/javascript, */*; q=0.01' \
  -H 'content-type: application/json' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' \
  -H 'sec-ch-ua-platform: "Windows"' \
  -H 'origin: https://blog.csdn.net' \
  -H 'sec-fetch-site: cross-site' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-dest: empty' \
  -H 'referer: https://blog.csdn.net/qq_35754976/article/details/120456967' \
  -H 'accept-language: zh-CN,zh;q=0.9,zh-TW;q=0.8,en-US;q=0.7,en;q=0.6' \
  --compressed

保存退出然后执行以下命令测试并发,windows可以找工具或者postman队列执行(postman参考该链接

# 并发测试接口实用性  a.sh里面是curl数据
for i in {1..100}
do
    sh a.sh >/dev/null &
done

下图代表成功,然后再次访问程序是否还会卡死的现象
在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:28:59  更:2022-05-18 17:29:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:37:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码