Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。DruidDataSource支持的数据库:
理论上说,支持所有有jdbc驱动的数据库。实际测试过的有
数据库 | 支持状态 |
mysql | 支持,大规模使用 |
oracle | 支持,大规模使用 |
sqlserver | 支持 |
postgres | 支持 |
db2 | 支持 |
h2 | 支持 |
derby | 支持 |
sqlite | 支持 |
sybase | 支持 |
更新:最新druid-spring-boot-starter的使用戳-->druid-spring-boot-starter:1.1.10
可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter-Chain机制,很方便编写JDBC层的扩展插件
1 更新pom.xml
com.microsoft.sqlserver
sqljdbc4
4.2
com.alibaba
druid
1.0.29
说明:sqljdbc4不能直接通过Maven下载,需要自己去官网下载了之后即将jar包放到repository\com\microsoft\sqlserver\sqljdbc4\4.2目录下,这个问题可以通过查看日志和百度找到位置。
2 更新application.properties或者是application.yml文件
application.properties:
#配置上下文,根据自己项目设置
server.contextPath=/MavenSpringBoot
#配置tomcat插件启动端口号
#server.port=8081
#中文及编码配置
#server.tomcat.uri-encoding=UTF-8
#spring.http.encoding.charset=UTF-8
#spring.http.encoding.enabled=true
#spring.http.encoding.force=true
#spring.messages.encoding=UTF-8
#配置DataSource,使用druid
#需要注意的是:spring.datasource.type属性,旧的spring boot版本是不能识别的。
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://localhost:1433; DatabaseName=test
spring.datasource.username=test
spring.datasource.password=123456
# 连接池的配置信息
# 初始化大小,最小,最大
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.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
application.yml:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://localhost:1433; DatabaseName=test
username: test
password: 123456
# 连接池的配置信息
# 初始化大小,最小,最大
initialSize: 5
minIdle: 5
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
3 配置Druid
由于Druid暂时不在Spring Boot中的直接支持,故需要进行配置信息的定制:
1)config:
package test.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
public class DruidDBConfig {
private Logger logger = Logger.getLogger(this.getClass()); //log4j日志
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
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;
@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);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
}
2)filter:
package test.filter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import com.alibaba.druid.support.http.WebStatFilter;
@WebFilter(filterName="druidWebStatFilter",urlPatterns="/*",
initParams={
@WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")//忽略资源
}
)
public class DruidStatFilter extends WebStatFilter {
}
3)servlet:
package test.servlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import com.alibaba.druid.support.http.StatViewServlet;
@WebServlet(urlPatterns="/druid/*",
initParams={
@WebInitParam(name="allow",value="127.0.0.1,192.168.163.1"),// IP白名单(没有配置或者为空,则允许所有访问)
@WebInitParam(name="deny",value="192.168.1.73"),// IP黑名单 (存在共同时,deny优先于allow)
@WebInitParam(name="loginUsername",value="admin"),// 用户名
@WebInitParam(name="loginPassword",value="123456"),// 密码
@WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能
})
public class DruidStatViewServlet extends StatViewServlet {
private static final long serialVersionUID = -2688872071445249539L;
}
启动类:SpringApplication(注意添加@ServletComponentScan)
package test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
// 返回json字符串的数据,直接可以编写RESTFul的接口
@RestController
// @SpringBootApplication声明让spring boot自动给程序进行必要的配置
@SpringBootApplication
// 添加servlet组件扫描,使得Spring能够扫描到我们编写的servlet和filter
@ServletComponentScan
public class SpringBootApp {
public static void main(String[] args) {
SpringApplication.run(SpringBootApp.class, args);
}
}
4 编写使用druid的DAO层
1)interface:
package test.interf;
import java.util.List;
import test.bean.Account;
public interface IAccountDAO {
int add(Account account);
int update(Account account);
int delete(int id);
Account findAccountById(int id);
List findAccountList();
}
package test.interf;
import java.util.List;
import test.bean.Account;
public interface IAccountService {
int add(Account account);
int update(Account account);
int delete(int id);
Account findAccountById(int id);
List findAccountList();
}
2)impl:
package test.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import test.bean.Account;
import test.interf.IAccountDAO;
import java.util.List;
@Repository
@Configuration
@Component
public class AccountDaoImpl implements IAccountDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int add(Account account) {
return jdbcTemplate.update("insert into account(name, money) values(?, ?)",
account.getName(),account.getMoney());
}
@Override
public int update(Account account) {
return jdbcTemplate.update("UPDATE account SET NAME=? ,money=? WHERE id=?",
account.getName(),account.getMoney(),account.getId());
}
@Override
public int delete(int id) {
return jdbcTemplate.update("DELETE from TABLE account where id=?",id);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Account findAccountById(int id) {
List list = jdbcTemplate.query("select * from account where id = ?", new Object[]{id}, new BeanPropertyRowMapper(Account.class));
if(list!=null && list.size()>0){
Account account = list.get(0);
return account;
}else{
return null;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public List findAccountList() {
List list = jdbcTemplate.query("select * from account", new Object[]{}, new BeanPropertyRowMapper(Account.class));
if(list!=null && list.size()>0){
return list;
}else{
return null;
}
}
}
3)service:
package test.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import test.bean.Account;
import test.interf.IAccountDAO;
import test.interf.IAccountService;
@Service
public class AccountService implements IAccountService {
@Autowired
@Qualifier("accountDaoImpl")
private IAccountDAO accDaoImpl;
@Override
public int add(Account account) {
return accDaoImpl.add(account);
}
@Override
public int update(Account account) {
return accDaoImpl.update(account);
}
@Override
public int delete(int id) {
return accDaoImpl.delete(id);
}
@Override
public Account findAccountById(int id) {
return accDaoImpl.findAccountById(id);
}
@Override
public List findAccountList() {
return accDaoImpl.findAccountList();
}
}
4)controller:
package test.controller;
import org.springframework.web.bind.annotation.RestController;
import test.bean.Account;
import test.interf.IAccountService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
public class HelloController {
@Autowired
//使用@Qualifier来提示Spring该用什么类型的数据填充该变量IoC
@Qualifier("accountService")
private IAccountService accService;
@RequestMapping("/accService")
public List getAccounts(){
return accService.findAccountList();
}
}
5 运行测试
首先需要建表:
create table account(
id int,
name nvarchar(10),
money float
)
insert account values(1,'yunlingfly',1.2)
insert account values(2,'test',1.6)
输入http://127.0.0.1:8080/MavenSpringBoot/druid/login.html
输入账户:admin 密码:123456 这是在servlet里设置的,可修改与数据库管理员登录那个可以不一致
结果:
保持服务器运行再开一个页面输入http://127.0.0.1:8080/MavenSpringBoot/accService
结果:
再次查看druid:
附:常见问题处理:https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98