springboot 多数据源+druid+ MyBatis+分页插件

第一步:

需要禁止掉springboot自生的DataSourceAutoConfiguration
因为它会默认会读取application.properties文件的spring.datasource.*属性并自动配置单数据源。
启动类上的注解修改为:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

第二步

修改配置文件,增加多数据源

#  第一数据库
spring.datasource.pay.url=127.0.0.1:3306
spring.datasource.pay.username=lucode
spring.datasource.pay.password=123
spring.datasource.pay.initialSize=5
spring.datasource.pay.maxActive=20
spring.datasource.pay.minIdle=1
spring.datasource.pay.maxWait=30000
spring.datasource.pay.timeBetweenEvictionRunsMillis=60000
spring.datasource.pay.minEvictableIdleTimeMillis=300000
spring.datasource.pay.poolPreparedStatements=true
spring.datasource.pay.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.pay.filters=stat, wall, config

# 第二个数据库
spring.datasource.travel.url=99.99.99.99:3306
spring.datasource.travel.username=lucode
spring.datasource.travel.password=123
spring.datasource.travel.initialSize=5
spring.datasource.travel.maxActive=20
spring.datasource.travel.minIdle=1
spring.datasource.travel.maxWait=30000
spring.datasource.travel.timeBetweenEvictionRunsMillis=60000
spring.datasource.travel.minEvictableIdleTimeMillis=300000
spring.datasource.travel.poolPreparedStatements=true
spring.datasource.travel.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.travel.filters=stat, wall, config

第三步

Druid数据源读取配置文件或者普通数据源配置

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@ConfigurationProperties(prefix = "spring.datasource.pay")
public class DruidConfigMetroPay {
    public String onoff;
    public String url;
    public String username;
    public String password;
    public int initialSize;
    public int maxActive;
    public int minIdle;
    public long maxWait;
    public long timeBetweenEvictionRunsMillis;
    public long minEvictableIdleTimeMillis;
    public boolean poolPreparedStatements;
    public int maxPoolPreparedStatementPerConnectionSize;
    public String filters;
    public String connectionProperties;

    public DruidConfigMetroPay() {
    }

    public DruidConfigMetroPay(String url, String username, String password, int initialSize, int maxActive, int minIdle,
                               long maxWait, long timeBetweenEvictionRunsMillis, long minEvictableIdleTimeMillis,
                               boolean poolPreparedStatements, int maxPoolPreparedStatementPerConnectionSize) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.initialSize = initialSize;
        this.maxActive = maxActive;
        this.minIdle = minIdle;
        this.maxWait = maxWait;
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
        this.poolPreparedStatements = poolPreparedStatements;
        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;

    }

    @Bean(name="druidDataSourceMetroPay")
    public DataSource druidDataSourceMetroPay() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setInitialSize(initialSize);
        druidDataSource.setMaxActive(maxActive);
        druidDataSource.setMinIdle(minIdle);
        druidDataSource.setMaxWait(maxWait);
        druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        druidDataSource.setConnectionProperties(connectionProperties);
        try {
            druidDataSource.setFilters("stat,slf4j");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            druidDataSource.setFilters(filters);
            druidDataSource.init();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }
//  此处省略 get/set 方法
}

注意:

  • druidDataSourceMetroPay() 这个方法的 Bean最好加一下命名。
  • ConfigurationProperties 的prefix 指定自定义配置的前缀。如果不嫌麻烦,可以一个一个注入到成员变量。
    同理另外一个德鲁伊数据源
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@ConfigurationProperties(prefix = "spring.datasource.travel")
public class DruidConfigMetroTravel {

    public String onoff;
    public String url;
    public String username;
    public String password;
    public int initialSize;
    public int maxActive;
    public int minIdle;
    public long maxWait;
    public long timeBetweenEvictionRunsMillis;
    public long minEvictableIdleTimeMillis;
    public boolean poolPreparedStatements;
    public int maxPoolPreparedStatementPerConnectionSize;
    public String filters;
    public String connectionProperties;

    public DruidConfigMetroTravel() {
    }

    public DruidConfigMetroTravel(String url, String username, String password, int initialSize, int maxActive, int minIdle,
                                  long maxWait, long timeBetweenEvictionRunsMillis, long minEvictableIdleTimeMillis,
                                  boolean poolPreparedStatements, int maxPoolPreparedStatementPerConnectionSize) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.initialSize = initialSize;
        this.maxActive = maxActive;
        this.minIdle = minIdle;
        this.maxWait = maxWait;
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
        this.poolPreparedStatements = poolPreparedStatements;
        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;

    }

    @Bean(name="druidDataSourceMetroTravel")
    public DataSource druidDataSourceMetroPay() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setInitialSize(initialSize);
        druidDataSource.setMaxActive(maxActive);
        druidDataSource.setMinIdle(minIdle);
        druidDataSource.setMaxWait(maxWait);
        druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        druidDataSource.setConnectionProperties(connectionProperties);
        try {
            druidDataSource.setFilters("stat,slf4j");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            druidDataSource.setFilters(filters);
            druidDataSource.init();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }

这样就定义了两个德鲁伊数据源了.
我们分别命名为druidDataSourceMetroPaydruidDataSourceMetroTravel
两个数据源对应着配置上的两个数据库。

第四步

下面简单整合一下德鲁伊的基础配置,只是简单做一个用户名密码的的配置,详细配置.....不说了。
值得注意的是这个配置必须优先,所以必须加上@Order这个配置。

import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
 * @author yunfeng.lu
 * @create 2017/12/28.
 */
@Configuration
public class DruidServletConfig {
    @Bean
    @Order
    public ServletRegistrationBean statViewServlet() {
        StatViewServlet servlet = new StatViewServlet();
        ServletRegistrationBean bean = new ServletRegistrationBean(servlet, "/druid/*");
        bean.addInitParameter("loginUsername", "lucode");
        bean.addInitParameter("loginPassword", "lucode123");
        return bean;
    }
}

第五步

注册MyBatis分页插件PageHelper

@Configuration
public class MybatisPageHelperConfig {
    @Bean
    public PageInterceptor pageHelper() {
        PageInterceptor pageHelper = new PageInterceptor();
        Properties p = new Properties();
        p.setProperty("offsetAsPageNum", "true");
        p.setProperty("rowBoundsWithCount", "true");
        p.setProperty("reasonable", "true");
        pageHelper.setProperties(p);
        return pageHelper;
    }
}

第六步

最后一步,也是将Druid数据源整合到 MyBatis 上以及pageHelper的整合。

import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
/**
 * @author yunfeng.lu
 * @create 2017/12/28.
 */
@MapperScan(basePackages = "com.lucode.**.dao.pay",
        sqlSessionFactoryRef = "sqlSessionFactoryMetroPay",
        sqlSessionTemplateRef = "sqlSessionTemplateMetroPay")
@Configuration
public class MyBatisConfigMetroPay {
//    如果不集成  德鲁伊数据库连接池,需要使用普通的数据源,也在这里配置
//    @Autowired
//    @Qualifier("metroPay")
//    private DataSource dataSourceMetroPay;

    /**
     * 德鲁伊数据源
     */
    private final DataSource druidDataSourceMetroPay;

    private final PageInterceptor pageHelper;

    @Autowired
    public MyBatisConfigMetroPay(@Qualifier("druidDataSourceMetroPay") DataSource druidDataSourceMetroPay, PageInterceptor pageHelper) {
        this.druidDataSourceMetroPay = druidDataSourceMetroPay;
        this.pageHelper = pageHelper;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryMetroPay() throws Exception {

        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(druidDataSourceMetroPay);
        sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(
                resolver.getResources("classpath*:com/lucode/**/dao/pay/*.xml"));

        SqlSessionFactory sqlSessionFactory = null;
        try {
            sqlSessionFactory = sqlSessionFactoryBean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
        org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
        configuration.setMapUnderscoreToCamelCase(true);
        return sqlSessionFactoryBean.getObject();
    }

    @Bean("metroPayTransaction")
    public DataSourceTransactionManager transactionManager() throws Exception {
        return new DataSourceTransactionManager(druidDataSourceMetroPay);
    }
    @Bean
    public SqlSessionTemplate sqlSessionTemplateMetroPay() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryMetroPay());
    }
}

解释一下

  • MyBatisConfigMetroPay 的构造方法,完成了DataSource,PageInterceptor的注入,注意的是 DataSource的注入需要标注一下注入 bean 的名字,也就是刚刚上面配置的 Bean 的名字druidDataSourceMetroPay。

  • MapperScan 这个扫描注解,需要配置扫描的路径,这里多说一下,多数据源的 dao 层,两个数据库的 dao,需要分开放,比如我们这里分了 travel 和 pay 两个包放 xxxmapper.xml和xxxmapper.java


    image.png

    至于 pojo 随便你,放在一起也没事。

  • sqlSessionFactoryMetroPay和sqlSessionTemplateMetroPay其实配置一也就可以,但是你配置两个系统会忽略一个。

  • transactionManager()这个方法需要特别注意的,这个事务相关的,如果不配置这个,开启事务的时候,就会出问题。
    配置也比较简单,标注一下 Bean 的明细,将数据源赋值进去即可。
    那我们在业务层使用声明式事务注解如何使用呢?

@Transactional(propagation = Propagation.REQUIRED, 
rollbackFor = Exception.class,
transactionManager = "metroPayTransaction")// 就是在这里指定一下事务
    public void transferCancel(InsideTransferConfirmModel model) {
      //忽略方法具体内容
}

同理另外一个数据库的就在配置一个
最后文件是这样的


image.png

DruidConfigMetroPay和DruidConfigMetroTravel 完成德鲁伊数据源的配置

DruidServletConfig和MybatisPageHelperConfig分别完成德鲁伊和分页插件的配置

MyBatisConfigMetroTravel和MyBatisConfigMetroPay最后完成他们的整合

至于DataSourceConfig其实是不适用德鲁伊数据库连接池数据源的配置

@Configuration
public class DataSourceConfig {
    @Bean(name = "metroPay")
    @ConfigurationProperties(prefix = "spring.datasource.pay")
    public DataSource dataSourceMetroPay() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "metroTravel")
    @ConfigurationProperties(prefix = "spring.datasource.travel")
    public DataSource dataSourceMetroTravel() {
        return DataSourceBuilder.create().build();
    }

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

推荐阅读更多精彩内容