SpringBoot用Druid整合MyBatis

来源:互联网 发布:阿里云备案拍照怎么拍 编辑:程序博客网 时间:2024/04/28 18:14

Druid介绍

Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。

Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计SQL信息、SQL性能收集、SQL注入检查、SQL翻译等,程序员可以通过定制来实现自己需要的功能。

Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。
Druid支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。
Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化
首先,强大的监控特性,通过Druid提供的监控功能,可以清楚知道连接池和SQL的工作情况。
  • 监控SQL的执行时间、ResultSet持有时间、返回行数、更新行数、错误次数、错误堆栈信息。
  • SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  • SQL执行的耗时区间分布。什么是耗时区间分布呢?比如说,某个SQL执行了1000次,其中0~1毫秒区间50次,1~10毫秒800次,10~100毫秒100次,100~1000毫秒30次,1~10秒15次,10秒以上5次。通过耗时区间分布,能够非常清楚知道SQL的执行耗时情况。
  • 监控连接池的物理连接创建和销毁次数、逻辑连接的申请和关闭次数、非空等待次数、PSCache命中率等。

其次,方便扩展。Druid提供了Filter-Chain模式的扩展API,可以自己编写Filter拦截JDBC中的任何方法,可以在上面做任何事情,比如说性能监控、SQL审计、用户名密码加密、日志等等。

Druid内置提供了用于监控的StatFilter、日志输出的Log系列Filter、防御SQL注入攻击的WallFilter。

阿里巴巴内部实现了用于数据库密码加密的CirceFilter,以及和Web、Spring关联监控的DragoonStatFilter。

第三,Druid集合了开源和商业数据库连接池的优秀特性,并结合阿里巴巴大规模苛刻生产环境的使用经验进行优化。

  • ExceptionSorter。当一个连接产生不可恢复的异常时,例如Oracle error_code_28 session has been killed,必须立刻从连接池中逐出,否则会产生大量错误。目前只有Druid和JBoss DataSource实现了ExceptionSorter。
  • PSCache内存占用优化对于支持游标的数据库(Oracle、SQL Server、DB2等,不包括MySql),PSCache可以大幅度提升SQL执行性能。一个PreparedStatement对应服务器一个游标,如果PreparedStatement被缓存起来重复执行,PreparedStatement没有被关闭,服务器端的游标就不会被关闭,性能提高非常显著。在类似“SELECT * FROM T WHERE ID = ?”这样的场景,性能可能是一个数量级的提升。但在Oracle JDBC Driver中,其他的数据库连接池(DBCP、JBossDataSource)会占用内存过多,极端情况可能大于1G。Druid调用OracleDriver提供管理PSCache内部API。
  • LRU是一个性能关键指标,特别Oracle,每个Connection对应数据库端的一个进程,如果数据库连接池遵从LRU,有助于数据库服务器优化,这是重要的指标。Druid、DBCP、Proxool、JBoss是遵守LRU的。BoneCP、C3P0则不是。BoneCP在mock环境下性能可能还好,但在真实环境中则就不好了。
Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。

简单SQL语句用时10微秒以内,复杂SQL用时30微秒。

通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。
Druid的优势是在JDBC最低层进行拦截做判断,不会遗漏。

项目下载(项目代码+数据库)

点击打开链接下载项目代码

运行结果展示

http://localhost:8080/selectUser.action?id=1

http://localhost:8080/druid/index.html             账号admin,密码admin,在代码中有体现的




项目构建

项目结构如图所示


添加依赖

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>SpringBoot_MyBatis_Diruid</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.7.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><!--热部署.jar --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><!-- druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.18</version></dependency><!-- thmleaf模板依赖. --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.2.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>



修改配置文件properties

#########################################spring datasource######################################spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=falsespring.datasource.username=rootspring.datasource.password=rootspring.datasource.driver-class-name=com.mysql.jdbc.Driver###############################下面Spring的配置文件基本就不用修改了spring.datasource.initialSize=5spring.datasource.minIdle=5spring.datasource.maxActive=20spring.datasource.maxWait=60000spring.datasource.timeBetweenEvictionRunsMillis=60000spring.datasource.minEvictableIdleTimeMillis=300000spring.datasource.validationQuery=SELECT 1 FROM DUALspring.datasource.testWhileIdle=truespring.datasource.testOnBorrow=falsespring.datasource.testOnReturn=falsespring.datasource.poolPreparedStatements=truespring.datasource.maxPoolPreparedStatementPerConnectionSize=20spring.datasource.filters=stat,wall,log4jspring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000#########################################spring thymeleaf######################################spring.thymeleaf.cache=false#########################################MyBatis######################################mybatis.mapper-locations=classpath:mapper/*Mapper.xml 


DruidConfigBean(重点)(重点)(重点)

druid有一个Servlet和Filter,这里采用编程注入的方式,

package com.example.demo.configBean;import java.util.HashMap;import java.util.Map;import javax.sql.DataSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;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 com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.support.http.StatViewServlet;import com.alibaba.druid.support.http.WebStatFilter;@Configurationpublic class DruidConfiguration {private static final Logger log = LoggerFactory.getLogger(DruidConfiguration.class);@Beanpublic ServletRegistrationBean druidServlet() {log.info("init Druid Servlet Configuration ");ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();servletRegistrationBean.setServlet(new StatViewServlet());servletRegistrationBean.addUrlMappings("/druid/*");Map<String, String> initParameters = new HashMap<String, String>();initParameters.put("loginUsername", "admin");// 用户名initParameters.put("loginPassword", "admin");// 密码initParameters.put("resetEnable", "false");// 禁用HTML页面上的“Reset All”功能initParameters.put("allow", ""); // IP白名单 (没有配置或者为空,则允许所有访问)// initParameters.put("deny", "192.168.20.38");// IP黑名单// (存在共同时,deny优先于allow)servletRegistrationBean.setInitParameters(initParameters);return servletRegistrationBean;}@Beanpublic FilterRegistrationBean filterRegistrationBean() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(new WebStatFilter());// 添加过滤规则filterRegistrationBean.addUrlPatterns("/*");// 添加不需要忽略的格式信息.filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");return filterRegistrationBean;}@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource() {return new DruidDataSource();}}


如果没有配置下面的Bean,它是不会监控到SQL语句的,就是不会有下面箭头指的地方

@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource() {return new DruidDataSource();}

dao

package com.example.demo.dao;import org.apache.ibatis.annotations.Mapper;import com.example.demo.entity.User;@Mapperpublic interface UserMapper {public User selectByPrimaryKey(Integer id);}

entity

package com.example.demo.entity;public class User {    private Integer id;    private String name;    private String username;    private String password;    private Integer sign;            public User() {}@Overridepublic String toString() {return "User [id=" + id + ", name=" + name + ", username=" + username + ", password=" + password + ", sign="+ sign + "]";}public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name == null ? null : name.trim();    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username == null ? null : username.trim();    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password == null ? null : password.trim();    }    public Integer getSign() {        return sign;    }    public void setSign(Integer sign) {        this.sign = sign;    }}



controller

package com.example.demo.handler;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.example.demo.dao.UserMapper;import com.example.demo.entity.User;@Controllerpublic class HelloHandler {@Autowiredprivate UserMapper  userMapper;@RequestMapping("/selectUser.action")public String selectUser(int id,Map<String,Object> map){User user=userMapper.selectByPrimaryKey(id);map.put("user", user);return "/success";}}


MyBatis中与dao对应的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="com.example.demo.dao.UserMapper" >  <resultMap id="BaseResultMap" type="com.example.demo.entity.User" >    <id column="id" property="id" jdbcType="INTEGER" />    <result column="name" property="name" jdbcType="VARCHAR" />    <result column="username" property="username" jdbcType="VARCHAR" />    <result column="password" property="password" jdbcType="VARCHAR" />    <result column="sign" property="sign" jdbcType="INTEGER" />  </resultMap>      <sql id="Base_Column_List" >    id, name, username, password, sign  </sql>  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >    select     <include refid="Base_Column_List" />    from user    where id = #{id,jdbcType=INTEGER}  </select> </mapper>


启动类

package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class SpringBootMyBatisDruidApplication {public static void main(String[] args) {SpringApplication.run(SpringBootMyBatisDruidApplication.class, args);}}


阅读全文
0 0
原创粉丝点击