Spring boot 2.0整合mybatis和druid数据源,基于starter方式

要点简介

  • 快速搭建基于mybatis和druid的spring boot 2.0工程
  • 聊聊druid数据源和2.0默认的HikariCP数据源
  • 聊聊starter 以及 不用starter方式配置的异同

一、起因

最近了解到spring boot2.0有很多新特性,比如支持基于响应式编程的spring webflux,于是准备在2.0上造一些轮子。但是每次搭建spring boot框架的时候,都会遇到数据源相关配置问题,以前也就是百度一下,也没有仔细的思考,所以这次也就特意整理了一下,理一理思路。

1.1 数据源的选择

  • 《为什么HikariCP被号称为性能最好的Java数据库连接池,如何配置使用》

  • spring boot 2.0将默认的数据源更换为HikariCP,HiKariCP是数据库连接池的一个后起之秀,号称性能最好,可以完美地PK掉其他连接池,是一个高性能的JDBC连接池,基于BoneCP做了不少的改进和优化。

  • 而druid具有丰富的sql拦截与监控统计功能,想知道你的系统都操作了哪些sql、执行时间怎么样,druid能告诉你细节

所以很多时候,为了开发方便,了解自己系统的短板,国内(包括我自己)很多时候还是选择的druid作为自己的数据源。

1.2 关于spring boot的starter

本节参考了博客《Spring Boot Starters》
https://www.nosuchfield.com/2017/10/15/Spring-Boot-Starters/

starter是 spring boot 提出的一个概念,在之前的工作中,我就有注意到应用了starter的项目在“某些”配置上可能就会简略不少,比如不用写java配置类了,也不用写xml配置文件了等等,可能很多时候我们都没有仔细思考过spring boot 提出这个概念的原因。StackOverflow有人描述了其中的思想。

Starter POMs are a set of convenient dependency descriptors that you can include in your application. You get a one-stop-shop for all the Spring and related technology that you need, without having to hunt through sample code and copy paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, just include the spring-boot-starter-data-jpa dependency in your project, and you are good to go.

1.2.1 未使用starter之前的做法

如果要集成mybatis和druid这两个工具,我们之前要

  • 引入druid依赖
  • 引入mybatis、mybatis-spring依赖
  • 使用java配置方式一次创建DataSource数据源、SqlSessionFactoryBean以及事务管理的类
//代码段 1.1 数据源配置类、mybatis配置类
@Configuration
public class DruidConfig {
    @Autowired
    private Environment env;
    @Primary
    @Bean
    @ConfigurationProperties("spring.datasource.druid")
    public DataSource dataSource(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties(prefix = "mybatis")
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapper-locations")));
        return sqlSessionFactoryBean;
    }

    /**
     * 注入 DataSourceTransactionManager 用于事务管理
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

}
<!--代码段1.2 这三个绝对不会少的POM依赖-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.0</version>
</dependency>
 <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.2</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>

1.2.2 Stater的原理

类似这样的配置层出不穷,而且不同的人写出的也不完全一样,有的非关键配置在部分博客里也添油加醋进去,通用性很差。所以,在这样的情况下,官方或者民间有些人就写了各种starter来简化我们的配置。

starter的理念:
starter会把所有用到的依赖都给包含进来,避免了开发者自己去引入依赖所带来的麻烦。需要注意的是不同的starter是为了解决不同的依赖,所以它们内部的实现可能会有很大的差异,例如jpa的starter和Redis的starter可能实现就不一样,这是因为starter的本质在于synthesize,这是一层在逻辑层面的抽象,也许这种理念有点类似于Docker,因为它们都是在做一个“包装”的操作,如果你知道Docker是为了解决什么问题的,也许你可以用Docker和starter做一个类比。

starter的实现:
虽然不同的starter实现起来各有差异,但是他们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfiguration。因为Spring Boot坚信“约定大于配置”这一理念,所以我们使用ConfigurationProperties来保存我们的配置,并且这些配置都可以有一个默认值,即在我们没有主动覆写原始配置的情况下,默认值就会生效,这在很多情况下是非常有用的。除此之外,starter的ConfigurationProperties还使得所有的配置属性被聚集到一个文件中(一般在resources目录下的application.properties),这样我们就告别了Spring项目中XML地狱。

spring-boot-stater原理

二、基于starter方式搭建

有了上面的认识,基于starter方式整合mybatis和druid就方便多了。一方面到目前为止,druid和mybatis官方都给出了starter的maven包以及配置范例。我们只需要在项目里依赖他们就可以使用了。下面依次是项目结构、pom文件以及boot的配置文件。


项目结构
<!--代码段1.3 pom文件-->
<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>
    <groupId>com</groupId>
    <artifactId>iview1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork><!-- 如果没有该项配置,肯呢个devtools不会起作用,即应用不会restart -->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
<!--代码段1.4 application.properites-->

#datasource
spring.datasource.druid.url=jdbc:mysql://localhost:3306/iview?characterEncoding=utf8&allowMultiQueries=true
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.type = com.alibaba.druid.pool.DruidDataSource
#mapper.xml文件所在地址-位于resource下面的mapper文件夹下
mybatis.mapper-locations=classpath:mapper/*/*.xml
#log日志级别
logging.level.com=debug
<!--代码段1.5 UserMapper-->
@Mapper
@Repository
public interface UserMapper {

    User getUserById(@Param("id")Integer id);
}

<!--代码段1.6 UserMapper.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">

<!-- 指定工作空间,要与接口名相同,源代码没有去看,猜测应该是通过"这里的namespace.下边方法的id"来定位方法的 -->
<mapper namespace="com.system.dao.UserMapper">
    <select id="getUserById"   resultType="com.system.model.User">
        select * from user where id = #{id}
    </select>
</mapper>

最后就是不要忘了,在启动类文件中,标明要扫描的mapper的位置MapperScan注解

<!--代码段1.7 启动文件-->
@SpringBootApplication
@ComponentScan(basePackages = "com")
@MapperScan("com.*.dao")
public class IviewApplication {

    public static void main(String[] args){
        SpringApplication.run(IviewApplication.class);
    }

}

这样配置就算完了,没有关于数据源的任何配置。启动的时候你可以看到日志提示

2018-07-23 22:04:14.686  INFO 7188 --- [           main] c.a.d.s.b.a.DruidDataSourceAutoConfigure : Init DruidDataSource
2018-07-23 22:04:14.842  INFO 7188 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
2018-07-23 22:04:15.398  INFO 7188 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/getById]}" onto public com.system.model.User com.system.controller.LoginController.getById(java.lang.Integer)
2018-07-23 22:04:15.399  INFO 7188 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/dologin],methods=[POST]}" onto public java.lang.String com.system.controller.LoginController.login(com.system.model.User)

访问controller的时候也有sql日志打出

2018-07-23 22:05:45.146 DEBUG 7188 --- [nio-8090-exec-1] com.system.dao.UserMapper.getUserById    : ==>  Preparing: select * from user where id = ? 
2018-07-23 22:05:45.164 DEBUG 7188 --- [nio-8090-exec-1] com.system.dao.UserMapper.getUserById    : ==> Parameters: 1(Integer)
2018-07-23 22:05:45.201 DEBUG 7188 --- [nio-8090-exec-1] com.system.dao.UserMapper.getUserById    : <==      Total: 1

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容