当时是基于C3P0处理数据库,然后偶发性出现连接超时,然后加上需要查看连接次数以及访问次数,我就想到采用druid数据库连接池,话不多说,先上代码
官网传送门:https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
其实下面的部分出于演示,用硬编码,其实完全可以通过配置属性,来进行动态改变,至于SpringCloud中的动态配置,其实也是通过重启SpringBoot来达到充值属性的效果,至于这部分,我之后会再说,这部分我也是看过某篇推文获悉
目录
配置数据库源:
1、pom.xml
2、application.properties
配置监控器
1、过滤不需要监控的后缀
2、监控视图配置
3、读取连接属性
4、测试:
StatFilter拓展(用于统计监控信息)
SQL合并配置
记录慢SQL
多个Druid数据源监控合并
配置防御SQL注入攻击
mysql
mysql-connector-java
com.alibaba
druid
1.1.11
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://*********************?allowMultiQueries=true&autoReconnect=true
spring.datasource.username=admin
spring.datasource.password=admin
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#dataSource Pool configuration
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.exceptionSorter=true
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.filters=stat,wall,log4j
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
spring.datasource.useGlobalDataSourceStat=true
对配置的属性不懂得的,可以https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_DruidDataSource%E5%8F%82%E8%80%83%E9%85%8D%E7%BD%AE 或则 参考 DruidDataSource.class
/**
* 配置监控拦截器
* druid监控拦截器
* @ClassName: DruidStatFilter
* @author CoffeeAndIce
* @date 2017年7月24日 上午10:53:40
*/
@WebFilter(filterName="druidWebStatFilter",
urlPatterns="/*",
initParams={
@WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"),// 忽略资源
})
public class DruidStatFilter extends WebStatFilter {
}
有人想在这里直接继承StatFilter进行操作,但是这样会导致重复导入,导致无法运行,因为Druid之前已经有将其置入。
/**
* druid监控视图配置
* @ClassName: DruidStatViewServlet
* @author CoffeeAndIce
* @date 2017年7月24日 上午10:54:27
*/
@WebServlet(urlPatterns = "/druid/*", initParams={
@WebInitParam(name="allow",value=""),// IP白名单 (没有配置或者为空,则允许所有访问)
@WebInitParam(name="deny",value="192.168.16.111"),// IP黑名单 (存在共同时,deny优先于allow)
@WebInitParam(name="loginUsername",value="admin"),// 用户名
@WebInitParam(name="loginPassword",value="admin"),// 密码
@WebInitParam(name="resetEnable",value="true")// 禁用HTML页面上的“Reset All”功能
})
public class DruidStatViewServlet extends StatViewServlet {
private static final long serialVersionUID = 2359758657306626394L;
}
如果仅仅这样配置,我这边不知道为什么和网上的不一样,我这边是用MyBatis来做数据处理的,这边就sql监控和sql防火墙监控都没有用,当前使用的spring boot版本为1.4.x版本
然后搜索了一番,数据源决定自己处理
(这是之前的写法)方式一
@Configuration
public class DruidConfiguration {
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driverClassName}")
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.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("${spring.datasource.connectionProperties}")
private String connectionProperties;
@Value("${spring.datasource.useGlobalDataSourceStat}")
private boolean useGlobalDataSourceStat;
@Bean //声明其为Bean实例
@Primary //在同样的DataSource中,首先使用被标注的DataSource
public DataSource dataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
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.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
System.err.println("druid configuration initialization filter: "+ e);
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
}
感谢读者给出的建议,同时让我学会了很多注解的应用玉机制,方式二
@SpringBootApplication
@ServletComponentScan//这行是为了避免扫描不到Druid的Servlet
public class WebBootApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(WebBootApplication.class, args);
}
/**
*
* 其实大家主要关心下面的就好
*/
@Bean("duridDatasource")
@ConfigurationProperties(prefix="spring.datasource")
public DataSource druidDataSource() { return new DruidDataSource(); }
}
连入 :http://localhost:8080/druid/login.html
输入(3.2、监控视图配置)设置的密码,终于看到梦寐以求的数据,这个问题可能是只有这个版本才有或者有其他处理方法
注意:上面的这个类需要放到和application同级的目录下,这样才能在程序启动的时候初始化DataSource
Tips: 在druid-0.2.17版本之后,sql合并支持tddl,能够对分表进行合并。
当你程序中存在没有参数化的sql执行时,sql统计的效果会不好。比如:
select * from t where id = 1
select * from t where id = 2
select * from t where id = 3
在统计中,显示为3条sql,这不是我们希望要的效果。StatFilter提供合并的功能,能够将这3个SQL合并为如下的SQL
select * from t where id = ?
spring.datasource.connectionProperties=druid.stat.mergeSql=true 属性配置是这样
之前的版本 可能是true,现在为false
/**
* @author wenshao [[email protected]]
*/
public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
private final static Log LOG = LogFactory.getLog(StatFilter.class);
private static final String SYS_PROP_LOG_SLOW_SQL = "druid.stat.logSlowSql";
private static final String SYS_PROP_SLOW_SQL_MILLIS = "druid.stat.slowSqlMillis";
private static final String SYS_PROP_MERGE_SQL = "druid.stat.mergeSql";
public final static String ATTR_NAME_CONNECTION_STAT = "stat.conn";
public final static String ATTR_TRANSACTION = "stat.tx";
private final Lock lock = new ReentrantLock();
// protected JdbcDataSourceStat dataSourceStat;
@Deprecated
protected final JdbcStatementStat statementStat = JdbcStatManager.getInstance().getStatementStat();
@Deprecated
protected final JdbcResultSetStat resultSetStat = JdbcStatManager.getInstance().getResultSetStat();
private boolean connectionStackTraceEnable = false;
// 3 seconds is slow sql
protected long slowSqlMillis = 3 * 1000;
protected boolean logSlowSql = false;
private String dbType;
private boolean mergeSql = false;
所以我们需要开启的话:
spring.datasource.connectionProperties=druid.stat.logSlowSql=true;
默认时间是3秒,如需要设置自定义值: druid.stat.slowSqlMillis 加上你需要的毫秒数
spring.datasource.useGlobalDataSourceStat=true
试中有其他问题或者解决方案,麻烦告知一下,共同进步,谢谢
https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE-wallfilter
开启过滤器的在开头已经给你开启了:spring.datasource.filters=wall
只要你下载了源码,搜索相应参数名:
eg: selelctAllow,你就会发现缺省值
public class WallConfig implements WallConfigMBean {
private boolean noneBaseStatementAllow = false;
private boolean callAllow = true;
private boolean selelctAllow = true;
private boolean selectIntoAllow = true;
private boolean selectIntoOutfileAllow = false;
private boolean selectWhereAlwayTrueCheck = true;
private boolean selectHavingAlwayTrueCheck = true;
private boolean selectUnionCheck = true;
private boolean selectMinusCheck = true;
private boolean selectExceptCheck = true;
private boolean selectIntersectCheck = true;
private boolean createTableAllow = true;
private boolean dropTableAllow = true;
private boolean alterTableAllow = true;
搜索:configFromProperties,你就会发现,如果这样还不会怎么配置,对不起,无能为力
Boolean propertyValue = getBoolean(properties, "druid.wall.selelctAllow");
if (propertyValue != null) {
this.setSelelctAllow(propertyValue);
}