Druid在SpringBoot下的使用

说明

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可以做什么?

        可以监控数据库访问性能,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

Druid在SpringBoot下的使用_第1张图片

 

输入账户:admin    密码:123456    这是在servlet里设置的,可修改与数据库管理员登录那个可以不一致

结果:

Druid在SpringBoot下的使用_第2张图片

保持服务器运行再开一个页面输入http://127.0.0.1:8080/MavenSpringBoot/accService

结果:

Druid在SpringBoot下的使用_第3张图片

再次查看druid:

Druid在SpringBoot下的使用_第4张图片

附:常见问题处理:https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98

你可能感兴趣的:(数据库连接池)