整合druid连接池
Druid简介
Druid是阿里出品的。
Druid是Java语言中最好的数据库连接池,能够提供强大的监控和扩展功能。
官方文档(英文):https://github.com/alibaba/druid/
本文 springboot 2.3.7.RELEASE + (mybatis2.1.3 +pagehelper)
来整合 Druid(1.1.22) 连接池
一、boot结构
表数据
二、集成示例
1.1、引入依赖
<!--
阿里druid连接池
1.1.23不能使用,大量ERROR问题:
discard long time none received connection
原因和方案:https://zhuanlan.zhihu.com/p/368683245
-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<!--mysql依赖8比5多了ssl-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<!-- StringUtils工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
1.2、配置文件application.properties
MySQL+druid+mybatis+pagehelper 详细配置
# 应用名称
spring.application.name=springtaskdemo
# 应用服务 WEB 访问端口
server.port=8080
#======================↓↓↓↓↓↓↓↓↓↓↓↓↓↓=======================================
# 配置数据源 mysql8
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone\=Asia/Shanghai&useUnicode\=true&characterEncoding\=utf8&allowMultiQueries\=true&rewriteBatchedStatements\=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# ===== ↓使用druid数据源↓ ========
# 注明:druid连接池springboot暂无法默认支持,需要自己配置bean
# 连接池类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 连接池初始化连接数量
spring.datasource.initialSize=5
# 连接池最小空闲数
spring.datasource.minIdle=5
# 连接池最大活跃连接数
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间(毫秒)
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=60000
# 连接是否有效的查询语句(心跳语句)
spring.datasource.validationQuery=SELECT 1 FROM DUAL
#........开始.................
# testOnBorrow和testOnReturn在生产环境一般是不开启的,主要是性能考虑。失效连接主要通过testWhileIdle
# 保证每次获取连接时候都要到数据库验证连接有效性, 这在高并发的时候会造成性能下降,可以将testOnBorrow设置成false,testWhileIdle设置成true这样能获得比较好的性能
# testWhileIdle默认true,则验证这条连接是否可用。
spring.datasource.testWhileIdle=true
# testOnBorrow默认为false,当应用向连接池申请连接时,连接池会判断这条连接是否是可用的
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
#.........结束................
# *********开始***********
#开发时候打开,上线关闭。poolPreparedStatements有可能会导致oom。内存泄露
#打开PSCache,并且指定每个连接上PSCache(游标)的大小 【poolPreparedStatements默认为 false】
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 生产环境中不要开启Druid的removeAbandoned配置,【默认fasle,开发调试用true】
spring.datasource.removeAbandoned=true
# *********结束***********
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,【 'stat':监控统计 'wall':用于防火墙,防御sql注入 'slf4j':日志 】
spring.datasource.filters=stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#useGlobalDataSourceStat: true # 合并多个DruidDataSource的监控数据(多数据源)
# SQL监控后台登录用户名-自定义
spring.datasource.loginUsername:admin
# SQL监控后台登录用户密码-自定义
spring.datasource.loginPassword:admin
#====================↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑===================================================
#======================↓↓↓↓mybatis配置-开始↓↓↓↓======================
# 映射文件xml的位置
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
# 使全局的映射器启用或禁用缓存
mybatis.configuration.cache-enabled=true
# 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载
mybatis.configuration.lazy-loading-enabled=true
# 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
mybatis.configuration.aggressive-lazy-loading=false
# 是否允许单条sql 返回多个数据集 (取决于驱动的兼容性) 默认:true
mybatis.configuration.multiple-result-sets-enabled=true
# 是否可以使用列的别名 (取决于驱动的兼容性) 默认:true
mybatis.configuration.use-column-label=true
# 指定MyBatis如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分 FULL:全部
mybatis.configuration.auto-mapping-behavior=partial
# 这是默认的执行类型 (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)
mybatis.configuration.default-executor-type=simple
# sql执行时间超时时间
mybatis.configuration.default-statement-timeout=25
# 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。
mybatis.configuration.safe-row-bounds-enabled=false
# 是否使用驼峰命名法转换字段
mybatis.configuration.map-underscore-to-camel-case=false
# 设置本地缓存范围 session:就会有数据的共享 statement:语句范围 (这样就不会有数据的共享 ) 默认:session
mybatis.configuration.local-cache-scope=session
# 设置当JDBC类型为空时,某些驱动程序 要指定值,默认:OTHER。当写入null值的字段时,部分数据库需要指定null的数据类型.mysql不用设置。【oracle需要设置】对应org.apache.ibatis.type.JdbcType的枚举值
mybatis.configuration.jdbc-type-for-null=other
# 指定对象哪个的方法触发一次延迟加载
mybatis.configuration.lazy-load-trigger-methods=equals,clone,hashCode,toString
# [默认false,推荐使用true] 如果数据为空的字段,则该字段省略不显示,查询数据映射数据类型使用的是Map。当字段值为null时,mybatis映射返回字段的时候会忽略,而原接口是null值也返回,为了兼容,需要设置不忽略null字段
mybatis.configuration.call-setters-on-nulls=true
# mybatis指定日志输出的前缀
mybatis.configuration.log-prefix=mybatis_
# 打印sql-开发时启用,会影响性能【使用boot默认的logback】
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 将java类型(javaType)转化为jdbc类型(jdbcType),或者将jdbc类型(jdbcType)转化为java类型(javaType)。【这个参数还没搞得很明白】
# mybatis.type-handlers-package=com.mapper.typehandler
# 允许JDBC生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 默认:false
# mybatis.configuration.use-generated-keys=false
# 指定代理工厂:mybatis 实现2个:CglibProxyFactory和JavassistProxyFactory(默认)
# mybatis.configuration.proxy-factory=CGLIB
#====================↑↑↑↑↑mybatis配置-结束↑↑↑↑↑↑===================================================
# pagehelper分页插件
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
1.3、编写druid配置类
package sqy.springtaskdemo.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.factory.annotation.Value;
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 org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* Druid核心配置类 - 注册bean
* Druid连接池监控平台 http://127.0.0.1:8080/druid/index.html
* @author suqinyi
* @Date 2022/1/10
*/
@Configuration
public class DruidConfig {
@Value("${spring.datasource.loginUsername}")
private String loginUsername;
@Value("${spring.datasource.loginPassword}")
private String loginPassword;
/**
* 配置Druid监控
*
* @param :
* @return: org.springframework.boot.web.servlet.ServletRegistrationBean
*/
@Bean
public ServletRegistrationBean druidServlet() {
// 注册服务
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// IP白名单(为空表示,所有的都可以访问,多个IP的时候用逗号隔开)
servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
// IP黑名单 (存在共同时,deny优先于allow)
servletRegistrationBean.addInitParameter("deny", "127.0.0.2");
// 设置控制台登录的用户名和密码
servletRegistrationBean.addInitParameter("loginUsername", loginUsername);
servletRegistrationBean.addInitParameter("loginPassword", loginPassword);
// 是否能够重置数据
servletRegistrationBean.addInitParameter("resetEnable", "false");
return servletRegistrationBean;
}
/**
* 配置web监控的filter
*
* @param :
* @return: org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
// 添加过滤规则
Map<String, String> initParams = new HashMap<>(1);
// 设置忽略请求
initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.addInitParameter("profileEnable", "true");
filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
filterRegistrationBean.addInitParameter("principalSessionName", "");
filterRegistrationBean.addInitParameter("aopPatterns", "sqy.springtaskdemo.service");
// 验证所有请求
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
/**
* 配置数据源 【 将所有前缀为spring.datasource下的配置项都加载到DataSource中 】
*
* @param :
* @return: javax.sql.DataSource
*/
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
/**
* 配置事物管理器
*
* @param :
* @return: org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
/**
* ↓↓↓↓↓↓ 配置spring监控 ↓↓↓↓↓↓
* DruidStatInterceptor: druid提供的拦截器
*
* @param :
* @return: com.alibaba.druid.support.spring.stat.DruidStatInterceptor
*/
@Bean
public DruidStatInterceptor druidStatInterceptor() {
DruidStatInterceptor dsInterceptor = new DruidStatInterceptor();
return dsInterceptor;
}
/**
* 使用正则表达式配置切点
*
* @param :
* @return: org.springframework.aop.support.JdkRegexpMethodPointcut
*/
@Bean
@Scope("prototype")
public JdkRegexpMethodPointcut druidStatPointcut() {
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern("sqy.springtaskdemo.controller.*");
return pointcut;
}
/**
* DefaultPointcutAdvisor类定义advice及 pointcut 属性。advice指定使用的通知方式,也就是druid提供的DruidStatInterceptor类,pointcut指定切入点
*
* @param druidStatInterceptor
* @param druidStatPointcut:
* @return: org.springframework.aop.support.DefaultPointcutAdvisor
*/
@Bean
public DefaultPointcutAdvisor druidStatAdvisor(DruidStatInterceptor druidStatInterceptor, JdkRegexpMethodPointcut druidStatPointcut) {
DefaultPointcutAdvisor defaultPointAdvisor = new DefaultPointcutAdvisor();
defaultPointAdvisor.setPointcut(druidStatPointcut);
defaultPointAdvisor.setAdvice(druidStatInterceptor);
return defaultPointAdvisor;
}
}
1.4、启动类扫描mapper包
1.5、实体类
user表
package sqy.springtaskdemo.pojo;
/**
* @author suqinyi
* @Date 2022/1/11
*/
public class User {
private Integer userId;
private String userName;
private String password;
//省略get、set、tostring
调度表
package sqy.springtaskdemo.pojo;
/**
* @author suqinyi
* @Date 2022/1/10
*/
public class MyCronTask {
private Integer cronId;
private String cronTime;
//省略get、set、tostring
}
1.6、Mybatis的xml方式
1.6.1、controller
package sqy.springtaskdemo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import sqy.springtaskdemo.pojo.User;
import sqy.springtaskdemo.service.UserService;
import java.util.List;
/**
* @author suqinyi
* @Date 2022/1/11
*/
@RestController
public class UserController {
@Autowired
UserService userService;
/**
* http://localhost:8080/findAllUser
* 基于xml方式(推荐)
*/
@GetMapping("/findAllUser")
public void findAll() {
List<User> list = userService.findAll();
System.out.println(list);
}
}
1.6.2、service
接口
package sqy.springtaskdemo.service;
import sqy.springtaskdemo.pojo.User;
import java.util.List;
/**
* @author suqinyi
* @Date 2022/1/11
*/
public interface UserService {
List<User> findAll();
}
实现
package sqy.springtaskdemo.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sqy.springtaskdemo.mapper.UserMapper;
import sqy.springtaskdemo.pojo.User;
import sqy.springtaskdemo.service.UserService;
import java.util.List;
/**
* @author suqinyi
* @Date 2022/1/11
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.findAll();
}
}
1.6.3、mapper接口和xml文件
mapper接口
package sqy.springtaskdemo.mapper;
import sqy.springtaskdemo.pojo.User;
import java.util.List;
/**
* @author suqinyi
* @Date 2022/1/11
* xml方式-推荐
*/
public interface UserMapper {
List<User> findAll();
}
xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="sqy.springtaskdemo.mapper.UserMapper">
<!-- 用户表的映射 -->
<resultMap id="UserResultMap" type="sqy.springtaskdemo.pojo.User">
<id column="user_id" jdbcType="INTEGER" property="userId"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
<result column="password" jdbcType="VARCHAR" property="password"/>
</resultMap>
<!--查找全部-->
<select id="findAll" resultType="sqy.springtaskdemo.pojo.User" resultMap="UserResultMap">
select * from user;
</select>
</mapper>
1.7、Mybatis的注解方式
这边controller和service和上面类似,就省略了
不同就只有mapper接口,注解方式不需要xml文件。
但是还是推荐xml方式比较好
mapper接口
package sqy.springtaskdemo.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import sqy.springtaskdemo.pojo.MyCronTask;
import java.util.List;
/**
* @author suqinyi
* @Date 2022/1/10
* 注解方式
*/
public interface CronMapper {
//查找注解。还有delete、insert、update...
@Select("select * from cron_task")
@Results(id="cronMap",value={
@Result(id=true,column = "cron_id",property = "cronId"),
@Result(column = "cron_time",property = "cronTime"),
})
List<MyCronTask> findAll();
}