Spring boot中多数据源Druid池配置及MyBatis配置

Spring boot中单一或多数据源Druid连接池的myBatis配置

数据源的通用配置方式,单一或多数据源,使用Druid连接池。当然配置中可以选择其他数据库连接池。当然Druid效率可能稍微差些,但其稳定性非常值得肯定,并且监控强大。本文代码完全可以使用在生成环境。

见jdbc.properties。配置中有两个

#datasource_1
spring.datasource.activity.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.activity.url=jdbc:mysql://10.99.11.252:3306/db_qiku_activity?useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.activity.username=root
spring.datasource.activity.password=qiku
spring.datasource.activity.driver-class-name=com.mysql.jdbc.Driver

#datasource_2
spring.datasource.theme.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.theme.url=jdbc:mysql://10.99.11.252:3306/db_test_themes?useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.theme.username=root
spring.datasource.theme.password=qiku
spring.datasource.theme.driver-class-name=com.mysql.jdbc.Driver

# DataSource DruidDataSource连接池的基本配置信息
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
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource.initialize=false

由于spring boot的自动配置中没有集成Druid数据库连接池,因此,第一步配置我们的datasorce

@Configuration  //Configuration  注解进行bean配置
@PropertySource(value = { "classpath:config/jdbc.properties"}, ignoreResourceNotFound=false) //引入jdbc文件,当然文件不可不存在
public class DruidConfig {

    //数据源1  由jdbc.properties自动注入属性值
    @Value("${spring.datasource.activity.url:#{null}}")
    private String acitvityDbUrl;
    @Value("${spring.datasource.activity.username: #{null}}")
    private String acitvityUsername;
    @Value("${spring.datasource.activity.password:#{null}}")
    private String acitvityPassword;
    @Value("${spring.datasource.activity.driverClassName:#{null}}")
    private String acitvityDriverClassName;

    //数据源2
    @Value("${spring.datasource.theme.url:#{null}}")
    private String themeDbUrl;
    @Value("${spring.datasource.theme.username: #{null}}")
    private String themeUsername;
    @Value("${spring.datasource.theme.password:#{null}}")
    private String themePassword;
    @Value("${spring.datasource.theme.driverClassName:#{null}}")
    private String themeDriverClassName;

    @Value("${spring.datasource.initialSize:#{null}}")
    private Integer initialSize;
    @Value("${spring.datasource.minIdle:#{null}}")
    private Integer minIdle;
    @Value("${spring.datasource.maxActive:#{null}}")
    private Integer maxActive;
    @Value("${spring.datasource.maxWait:#{null}}")
    private Integer maxWait;
    @Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
    private Integer timeBetweenEvictionRunsMillis;
    @Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
    private Integer minEvictableIdleTimeMillis;
    @Value("${spring.datasource.validationQuery:#{null}}")
    private String validationQuery;
    @Value("${spring.datasource.testWhileIdle:#{null}}")
    private Boolean testWhileIdle;
    @Value("${spring.datasource.testOnBorrow:#{null}}")
    private Boolean testOnBorrow;
    @Value("${spring.datasource.testOnReturn:#{null}}")
    private Boolean testOnReturn;
    @Value("${spring.datasource.poolPreparedStatements:#{null}}")
    private Boolean poolPreparedStatements;
    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
    private Integer maxPoolPreparedStatementPerConnectionSize;
    @Value("${spring.datasource.filters:#{null}}")
    private String filters;
    @Value("{spring.datasource.connectionProperties:#{null}}")
    private String connectionProperties;

    @Bean(name="themeDataSource", destroyMethod="close")     //声明其为Bean实例
    @Primary  //在同样的DataSource中,首先使用被标注的DataSource
    public DataSource themeDataSource() {
        //com.alibaba.druid.pool.DruidDataSource 使用druid的datasorce
        //在此处可以定义任何类型的数据库连接池的datasource
        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setUrl(this.themeDbUrl);
        dataSource.setUsername(this.themeUsername);
        dataSource.setPassword(this.themePassword);
        dataSource.setDriverClassName(this.themeDriverClassName);
        //configuration
        if (initialSize != null) {
            dataSource.setInitialSize(initialSize);
        }
        if (minIdle != null) {
            dataSource.setMinIdle(minIdle);
        }
        if (maxActive != null) {
            dataSource.setMaxActive(maxActive);
        }
        if (maxWait != null) {
            dataSource.setMaxWait(maxWait);
        }
        if (timeBetweenEvictionRunsMillis != null) {
            dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        }
        if (minEvictableIdleTimeMillis != null) {
            dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        }
        if (validationQuery != null) {
            dataSource.setValidationQuery(validationQuery);
        }
        if (testWhileIdle != null) {
            dataSource.setTestWhileIdle(testWhileIdle);
        }
        if (testOnBorrow != null) {
            dataSource.setTestOnBorrow(testOnBorrow);
        }
        if (testOnReturn != null) {
            dataSource.setTestOnReturn(testOnReturn);
        }
        if (poolPreparedStatements != null) {
            dataSource.setPoolPreparedStatements(poolPreparedStatements);
        }
        if (maxPoolPreparedStatementPerConnectionSize != null) {
            dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        }

        if (connectionProperties != null) {
            dataSource.setConnectionProperties(connectionProperties);
        }

        List<Filter> filters = new ArrayList<>();
        filters.add(statFilter());
        filters.add(wallFilter());
        dataSource.setProxyFilters(filters);   //此处添加了

        return dataSource;
    }

    @Bean(name="activityDataSource", destroyMethod="close")     //声明其为Bean实例
    @Primary  //在同样的DataSource中,首先使用被标注的DataSource
    public DataSource activityDataSource() {
        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setUrl(this.acitvityDbUrl);
        dataSource.setUsername(this.acitvityUsername);
        dataSource.setPassword(this.acitvityPassword);
        dataSource.setDriverClassName(this.acitvityDriverClassName);
        //configuration
        if (initialSize != null) {
            dataSource.setInitialSize(initialSize);
        }
        if (minIdle != null) {
            dataSource.setMinIdle(minIdle);
        }
        if (maxActive != null) {
            dataSource.setMaxActive(maxActive);
        }
        if (maxWait != null) {
            dataSource.setMaxWait(maxWait);
        }
        if (timeBetweenEvictionRunsMillis != null) {
            dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        }
        if (minEvictableIdleTimeMillis != null) {
            dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        }
        if (validationQuery != null) {
            dataSource.setValidationQuery(validationQuery);
        }
        if (testWhileIdle != null) {
            dataSource.setTestWhileIdle(testWhileIdle);
        }
        if (testOnBorrow != null) {
            dataSource.setTestOnBorrow(testOnBorrow);
        }
        if (testOnReturn != null) {
            dataSource.setTestOnReturn(testOnReturn);
        }
        if (poolPreparedStatements != null) {
            dataSource.setPoolPreparedStatements(poolPreparedStatements);
        }
        if (maxPoolPreparedStatementPerConnectionSize != null) {
            dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        }

        if (connectionProperties != null) {
            dataSource.setConnectionProperties(connectionProperties);
        }

        List<Filter> filters = new ArrayList<>();
        filters.add(statFilter());
        filters.add(wallFilter());
        dataSource.setProxyFilters(filters);  //此处设置该DruidDataSource的监控页面的servlet。

        return dataSource;
    }

    @Bean
    @Primary
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        //添加密码访问
        Map<String, String> initParameters = Maps.newHashMap();
        initParameters.put("loginUsername","admin");
        initParameters.put("loginPassword","admin");
        initParameters.put("resetEnable", "false");// 禁用HTML页面上的“Reset All”功能
        initParameters.put("allow", "127.0.0.1"); // IP白名单 (没有配置或者为空,则允许所有访问)
        //initParameters.put("deny", "192.168.20.38");// IP黑名单 (存在共同时,deny优先于allow)
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;
    }

    @Bean
    @Primary
    public StatFilter statFilter() {
        StatFilter statFilter = new StatFilter();
        statFilter.setLogSlowSql(true);
        statFilter.setMergeSql(true);
        statFilter.setSlowSqlMillis(1000);

        return statFilter;
    }

    @Bean
    @Primary
    public WallFilter wallFilter() {
        WallFilter wallFilter = new WallFilter();

        //允许执行多条SQL
        WallConfig config = new WallConfig();
        config.setMultiStatementAllow(true);
        wallFilter.setConfig(config);

        return wallFilter;
    }

//    @Bean
//    @Primary
//    public DataSourceTransactionManager transactionManager() {
//        return new DataSourceTransactionManager(this.activityDataSource());
//    }
}

上面的代码可以看出已经将配置的多个数据源信息注入,并生成datasource的bean供容器管理。
下面该配置mybatis的SqlSessionFactory,以及SqlSessionTemplate供mybatis框架进行管理。

@Configuration
public class DataSorceConfig {

    @Autowired
    @Qualifier("activityDataSource")
    private DataSource activityDataSource;

    @Autowired
    @Qualifier("themeDataSource")
    private DataSource themeDataSource;

    @Bean(name="activitySqlSessionFactory")
    //@ConditionalOnMissingBean //当容器里没有指定的Bean的情况下创建该对象
    public SqlSessionFactory activitySqlSessionFactory() throws Exception {

        //这里配置mybatis的SqlSessionFactory
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        //设置datasource
        bean.setDataSource(activityDataSource);
        //这里设置mybatis查询结果对应的对象地址
        bean.setTypeAliasesPackage("com.qihoo.lottery.vo.dt");
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        //使用jdbc的getGeneratedKeys获取数据库自增主键值
        configuration.setUseGeneratedKeys(true);
        //使用列别名替换列名 select user as User
        configuration.setUseColumnLabel(true);
        //-自动使用驼峰命名属性映射字段   userId    user_id
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setFailFast(true);
        return bean.getObject();
    }
    @Bean(name="themeSqlSessionFactory")
    //@ConditionalOnMissingBean //当容器里没有指定的Bean的情况下创建该对象
    public SqlSessionFactory themeSqlSessionFactory() throws Exception {

        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(themeDataSource);
        bean.setTypeAliasesPackage("com.qihoo.lottery.vo.dt");
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        //使用jdbc的getGeneratedKeys获取数据库自增主键值
        configuration.setUseGeneratedKeys(true);
        //使用列别名替换列名 select user as User
        configuration.setUseColumnLabel(true);
        //-自动使用驼峰命名属性映射字段   userId    user_id
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setFailFast(true);
        return bean.getObject();
    }
    @Bean
    public DataSourceTransactionManager activityDataSourceTransactionManager() {
        return new DataSourceTransactionManager(activityDataSource);
    }
    //配置每个数据源对应的SqlSessionTemplate供框架进行管理
    @Bean
    public SqlSessionTemplate activitySqlSessionTemplate(@Qualifier("activitySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory);
        return template;
    }
    @Bean
    public DataSourceTransactionManager themeDataSourceTransactionManager() {
        return new DataSourceTransactionManager(themeDataSource);
    }
    @Bean
    public SqlSessionTemplate themeSqlSessionTemplate(@Qualifier("themeSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory);
        return template;
    }
}

由以上代码可以看到两个数据源已经妥妥的被容器管理。
请问?请问可以SqlSessionFactoryBean可以直接加载mybatis的配置文件吗?那当然可以,样例代码给出的是程序方式配置。下面给出直接加载mybatis配置文件。

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource mybatisConfigXml = resolver.getResource("classpath:mybatis/mybatis-config.xml");
sqlSessionFactoryBean.setConfigLocation(mybatisConfigXml);

补充一点:本人的sql是通过注解注入,非xml文件。例如:

@Select("select count(*) from tb_qiku_activity_info")
public int selectActivityCount();

@UpdateProvider(type=ActivitySqlProvider.class, method="upActivity")
public int updateActivity(@Param("req") ActivityReq req);

sql通过注入方式因此无需加载xml文件。如果各位的sql是通过xml文件配置。需要设置mapper地址。

bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/designer/*.xml"));

完了?否!
需要制定每个数据源对于的mapper,即指定每个SqlSessionTemplate对于的mapper路径。

@Configuration
@AutoConfigureAfter(DataSorceConfig.class)  //这个注解很重要,必须是SqlSessionTemplate初始化完成,再初始化该maperrscanner
public class MapperScannerConfig {

    @Bean
    public MapperScannerConfigurer activityMapperScannerConfigurer() {

        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        //设置mapper对应template对应的mapper的代码路径。
        configurer.setSqlSessionTemplateBeanName("activitySqlSessionTemplate");
        configurer.setBasePackage("com.qihoo.lottery.dao.mapper.activity");
        return configurer;
    }
    @Bean
    public MapperScannerConfigurer themeMapperScannerConfigurer() {

        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setSqlSessionTemplateBeanName("themeSqlSessionTemplate");
        configurer.setBasePackage("com.qihoo.lottery.dao.mapper.theme");
        return configurer;
    }
}

通过上面的简单配置,多数据源就被Druid池管理起来。当然单一连接也就是在代码中对bean的增减问题。
以上只是一些简单的配置,其实就是就application.xml中的bean信息搬到代码中而已。
各位看客完全可以把以上代码搬移到自己的项目中。


技术为王
这里写图片描述

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页