Closed vieyahn2017 closed 6 years ago
springboot使用druid连接池,并配置数据源监控 https://segmentfault.com/a/1190000015564484
首先肯定是引入druid的依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
然后将druid配置到项目中:
在application.yml中加入
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
###数据源的其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
### 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
这里配置好之后,数据源是从默认的tomcat.pool切换到了druid,可是druid的属性比如initialSize、minIdle还未生效,因为在DataSourceProperties.class下没有对应的匹配项,所以还需要我们手动配置:
新建DruidConfig.java
@Configuration
public class DruidConfig {
// 将所有前缀为spring.datasource下的配置项都加载到DataSource中
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
}
至此,Druid的所有配置都已完成,打断点可以看到配置已经生效: clipboard.png clipboard.png
最后,需要配置druid的监控页面
在上面的DruidConfig中加入代码:
@Bean
public ServletRegistrationBean druidStatViewServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String, String> initParams = new HashMap<>();
// 可配的属性都在 StatViewServlet 和其父类下
initParams.put("loginUsername", "admin-druid");
initParams.put("loginPassword", "111111");
servletRegistrationBean.setInitParameters(initParams);
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean druidWebStatFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
打开浏览器测试输入:http://localhost:8080/druid/login.html
可以看到 clipboard.png
输入我们刚才在servlet中配置的账号密码就可以登录了
数据库阿里连接池 druid配置详解 https://blog.csdn.net/hj7jay/article/details/51686418
druid简单教程 https://blog.csdn.net/yunnysunny/article/details/8657095?utm_source=blogxgwz4
1 配置
2 代码编写
2.1 使用spring
2.2 不使用spring
类似于dbcp,druid也提供了原生态的支持。这里仅仅列出来了如何获取一个DataSource对象,实际使用中要将获取DataSource的过程封装到一个单体模式类中。先看下面这段代码:
///代码片段2.3 手动读取配置文件初始化连接池
package com.whyun.util.db;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.whyun.util.config.MySqlConfigProperty;
import com.whyun.util.config.MySqlConfigProperty2;
import com.whyun.util.db.source.AbstractDataSource;
import com.whyun.util.db.source.impl.DbcpSourceMysql;
import com.whyun.util.db.source.impl.DruidSourceMysql;
import com.whyun.util.db.source.impl.DruidSourceMysql2;
// TODO: Auto-generated Javadoc
/**
* The Class DataSourceUtil.
*/
public class DataSourceUtil {
/** 使用配置文件dbconfig.properties构建Druid数据源. */
public static final int DRUID_MYSQL_SOURCE = 0;
/** The duird mysql source. */
private static DataSource duirdMysqlSource;
/** 使用配置文件dbconfig2.properties构建Druid数据源. */
public static final int DRUID_MYSQL_SOURCE2 = 1;
/** The druid mysql source2. */
private static DataSource druidMysqlSource2;
/** 使用配置文件dbconfig.properties构建Dbcp数据源. */
public static final int DBCP_SOURCE = 4;
/** The dbcp source. */
private static DataSource dbcpSource;
/**
* 根据类型获取数据源.
*
* @param sourceType 数据源类型
* @return druid或者dbcp数据源
* @throws Exception the exception
* @NotThreadSafe
*/
public static final DataSource getDataSource(int sourceType)
throws Exception {
DataSource dataSource = null;
switch(sourceType) {
case DRUID_MYSQL_SOURCE:
if (duirdMysqlSource == null) {
duirdMysqlSource = DruidDataSourceFactory.createDataSource(
MySqlConfigProperty.getInstance().getProperties());
}
dataSource = duirdMysqlSource;
break;
case DRUID_MYSQL_SOURCE2:
if (druidMysqlSource2 == null) {
druidMysqlSource2 = DruidDataSourceFactory.createDataSource(
MySqlConfigProperty2.getInstance().getProperties());
}
dataSource = druidMysqlSource2;
break;
case DBCP_SOURCE:
if (dbcpSource == null) {
dbcpSource = BasicDataSourceFactory.createDataSource(
MySqlConfigProperty.getInstance().getProperties());
}
dataSource = dbcpSource;
break;
}
return dataSource;
}
/**
* 根据数据库类型标示获取DataSource对象,跟{@link com.whyun.util.db.DataSourceUtil#getDataSource(int)}
* 不同的是,这里DataSource获取的时候使用了单体模式
*
* @param sourceType 数据源类型
* @return 获取到的DataSource对象
* @throws Exception the exception
*/
public static final DataSource getDataSource2(int sourceType) throws Exception {
AbstractDataSource abstractDataSource = null;
switch(sourceType) {
case DRUID_MYSQL_SOURCE:
abstractDataSource = DruidSourceMysql.getInstance();
break;
case DRUID_MYSQL_SOURCE2:
abstractDataSource = DruidSourceMysql2.getInstance();
break;
case DBCP_SOURCE:
abstractDataSource = DbcpSourceMysql.getInstance();
break;
}
return abstractDataSource == null ?
null :
abstractDataSource.getDataSource();
}
}
第37行中调用了类com.alibaba.druid.pool.DruidDataSourceFactory中createDataSource方法来初始化一个连接池。对比dbcp的使用方法,两者很相似。
下面给出一个多线程的测试程序。运行后可以比较druid和dbcp的性能差别。
///代码片段2.4 连接池多线程测试程序
package com.whyun.druid.test;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.whyun.druid.model.TableOperator;
import com.whyun.util.db.DataSourceUtil;
public class MutilThreadTest {
public static void test(int dbType, int times)
throws Exception {
int numOfThreads =Runtime.getRuntime().availableProcessors()*2;
ExecutorService executor = Executors.newFixedThreadPool(numOfThreads);
final TableOperator test = new TableOperator();
// int dbType = DataSourceUtil.DRUID_MYSQL_SOURCE;
// dbType = DataSourceUtil.DBCP_SOURCE;
test.setDataSource(DataSourceUtil.getDataSource(dbType));
boolean createResult = false;
try {
test.createTable();
createResult = true;
} catch (SQLException e) {
e.printStackTrace();
}
if (createResult) {
List<Future<Long>> results = new ArrayList<Future<Long>>();
for (int i = 0; i < times; i++) {
results.add(executor.submit(new Callable<Long>() {
@Override
public Long call() throws Exception {
long begin = System.currentTimeMillis();
try {
test.insert();
//insertResult = true;
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
return end - begin;
}
}));
}
executor.shutdown();
while(!executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS));
long sum = 0;
for (Future<Long> result : results) {
sum += result.get();
}
System.out.println("---------------db type "+dbType+"------------------");
System.out.println("number of threads :" + numOfThreads + " times:" + times);
System.out.println("running time: " + sum + "ms");
System.out.println("TPS: " + (double)(100000 * 1000) / (double)(sum));
System.out.println();
try {
test.tearDown();
//dropResult = true;
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println("初始化数据库失败");
}
}
public static void main (String argc[])
throws Exception {
test(DataSourceUtil.DBCP_SOURCE,50);
test(DataSourceUtil.DRUID_MYSQL_SOURCE,50);
}
}
阿里Druid连接池监控的两个坑 https://blog.csdn.net/moakun/article/details/80055960?utm_source=blogxgwz0
问题1:不断打印error级别的错误日志
问题2:DruidStatView类异常
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:394)
at java.util.LinkedHashMap$ValueIterator.next(LinkedHashMap.java:409)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1067)
at com.alibaba.druid.support.http.stat.WebAppStat.getSessionStatDataList(WebAppStat.java:504)
at com.alibaba.druid.support.http.stat.WebAppStatUtils.getSessionStatDataList(WebAppStatUtils.java:64)
at com.alibaba.druid.support.http.stat.WebAppStatManager.getSessionStatData(WebAppStatManager.java:100)
at com.alibaba.druid.stat.DruidStatService.getWebSessionStatDataList(DruidStatService.java:205)
at com.alibaba.druid.stat.DruidStatService.service(DruidStatService.java:161)
at com.alibaba.druid.support.http.StatViewServlet.process(StatViewServlet.java:162)
at com.alibaba.druid.support.http.ResourceServlet.service(ResourceServlet.java:253)
看源码,发现又是session监控的坑
无力吐槽。。
for循环里面重复定义Map,可能在别的地方有元素变动,导致发生ConcurrentModificationException异常。
所以,最后关闭了session监控。
很好奇,阿里工程师都这种水平吗?还是为了偷懒?
DruidParser - 源代码篇(1)
2016年05月09日 13:44:39 张哈希 阅读数:8213 标签: druid sqlparser 源代码 初始化 个人分类: SQL解析器(Druid SQLParser) 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhxdick/article/details/51350854 最近用阿里的Druid的SQL parser来解析SQL语句。在此记录下研究: 调用它来解析出AST语意树一般这么写(针对MySQL):
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
for(SQLStatement statement:statementList){
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
statemen.accept(visitor);
}
对于每一个SQL请求(可能包含多语句),需要先新建一个MySqlStatementParser。注意,MySqlStatementParser 不是线程安全的,所以一种做法是针对每个session的请求,需要新建一个MySqlStatementParser。 那么这个初始化过程究竟是怎样的呢?涉及到哪些类?
涉及到的类如下所示: 这里写图片描述 SQL解析可以分为三层:语句解析->表达式解析->词法解析。对应的主要类分别是MySqlStatementParser,MySqlExprParser,MySqlLexer。可以说,MySqlLexer是解析出每个词的词义,表达式由词组成,MySqlExprParser用来解析出不同表达式的含义。多个表达式和词组成完整的语句,这个由MySqlStatementParser解析。
另有
,不是ali的数据库连接池 ...
springboot使用druid连接池,并配置数据源监控 https://segmentfault.com/a/1190000015564484