Spring Boot 中使用 MyBatis 整合 Druid 多數據源

本文將講述 spring boot + mybatis + druid 多數據源配置方案。css

環境

CentOs7.3 安裝 MySQL 5.7.19 二進制版本java

Github 代碼

代碼我已放到 Github ,導入spring-boot-mybatis 項目 mysql

github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-mybatisgit

 項目結構

添加依賴

在項目中添加 mybatis,druid 依賴github

點擊預覽 pom.xmlspring

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>
省略 更多

基礎數據源

@Configuration
@EnableConfigurationProperties(DruidDbProperties.class)
@Import({DruidMonitConfig.class})
public abstract class AbstractDruidDBConfig {

    private Logger logger = LoggerFactory.getLogger(AbstractDruidDBConfig.class);

    @Resource
    private DruidDbProperties druidDbProperties;

    public DruidDataSource createDataSource(String url, String username, String password) {
        if (StringUtils.isEmpty(url)) {
            System.out.println(
                    "Your database connection pool configuration is incorrect!" + " Please check your Spring profile");
            throw new ApplicationContextException("Database connection pool is not configured correctly");
        }

        DruidDataSource datasource = new DruidDataSource();

        datasource.setUrl(url);
        datasource.setUsername(username);
        datasource.setPassword(password);
        // datasource.setDriverClassName(
        // StringUtils.isEmpty(driverClassName) ?
        // druidDbProperties.getDriverClassName() : driverClassName);
        datasource.setInitialSize(druidDbProperties.getInitialSize());
        datasource.setMinIdle(druidDbProperties.getMinIdle());
        datasource.setMaxActive(druidDbProperties.getMaxActive());
        datasource.setMaxWait(druidDbProperties.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(druidDbProperties.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(druidDbProperties.getMinEvictableIdleTimeMillis());
        datasource.setValidationQuery(druidDbProperties.getValidationQuery());
        datasource.setTestWhileIdle(druidDbProperties.isTestWhileIdle());
        datasource.setTestOnBorrow(druidDbProperties.isTestOnBorrow());
        datasource.setTestOnReturn(druidDbProperties.isTestOnReturn());
        try {
            datasource.setFilters(druidDbProperties.getFilters());
        } catch (SQLException e) {
            logger.error("druid configuration initialization filter", e);
        }
        datasource.setConnectionProperties(druidDbProperties.getConnectionProperties());
        return datasource;

    }

    /**
     * 加載默認mybatis xml配置文件,並初始化分頁插件
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        return createSqlSessionFactory(dataSource, "classpath:mybatis/**/*.xml");
    }

    /**
     * 加載mybatis xml配置文件,並初始化分頁插件
     *
     * @param dataSource      數據源
     * @param mapperLocations 自定義xml配置路徑
     * @return
     * @throws Exception
     */
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource, String mapperLocations) throws Exception {
        return createSqlSessionFactory(dataSource, mapperLocations);
    }

    private SqlSessionFactory createSqlSessionFactory(DataSource dataSource, String mapperLocations) throws Exception {

        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        // mybatis分頁
        PageHelper pageHelper = new PageHelper();
        Properties props = new Properties();
        props.setProperty("dialect", "mysql");
        props.setProperty("reasonable", "true");
        props.setProperty("supportMethodsArguments", "true");
        props.setProperty("returnPageInfo", "check");
        props.setProperty("params", "count=countSql");
        pageHelper.setProperties(props); // 添加插件
        sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations));
        return sqlSessionFactoryBean.getObject();

    }
}

Druid 監控配置

@EnableConfigurationProperties(DruidDbProperties.class)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DruidMonitConfig {

    @Resource
    private DruidDbProperties druidDbProperties;

    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");

        if (!StringUtils.isEmpty(druidDbProperties.getAllow())) {
            reg.addInitParameter("allow", druidDbProperties.getAllow()); // 白名單
        }
        if (!StringUtils.isEmpty(druidDbProperties.getDeny())) {
            reg.addInitParameter("deny", druidDbProperties.getDeny()); // 黑名單
        }
        reg.addInitParameter("loginUsername", druidDbProperties.getUsername());
        reg.addInitParameter("loginPassword", druidDbProperties.getPassword());
        return reg;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }

    /**
     * 監聽Spring 1.定義攔截器 2.定義切入點 3.定義通知類
     *
     * @return
     */
    @Bean
    public DruidStatInterceptor druidStatInterceptor() {
        return new DruidStatInterceptor();
    }

    @Bean
    public JdkRegexpMethodPointcut druidStatPointcut() {
        JdkRegexpMethodPointcut druidStatPointcut = new JdkRegexpMethodPointcut();
        String patterns = "io.ymq.mybatis*";
        druidStatPointcut.setPatterns(patterns);
        return druidStatPointcut;
    }

    @Bean
    public Advisor druidStatAdvisor() {
        return new DefaultPointcutAdvisor(druidStatPointcut(), druidStatInterceptor());
    }
}

Druid 監控參數

@ConfigurationProperties(prefix = "druid")
public class DruidDbProperties {

    private String driverClassName = "com.mysql.jdbc.Driver";

    /**
     * 初始化時創建物理鏈接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時
     */
    private int initialSize = 10;

    /**
     * 最小鏈接池數量
     */
    private int minIdle = 50;

    /**
     * 最大鏈接池數量
     */
    private int maxActive = 300;

    /**
     * 獲取鏈接時最大等待時間,單位毫秒。配置了maxWait以後,缺省啓用公平鎖,併發效率會有所降低,若是須要能夠經過配置useUnfairLock屬性爲true使用非公平鎖。
     */
    private int maxWait = 60000;

    /**
     * 有兩個含義: 1)
     * Destroy線程會檢測鏈接的間隔時間,若是鏈接空閒時間大於等於minEvictableIdleTimeMillis則關閉物理鏈接。 2)
     * testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明
     */
    private int timeBetweenEvictionRunsMillis = 60000;

    /**
     * 鏈接保持空閒而不被驅逐的最長時間
     */
    private int minEvictableIdleTimeMillis = 3600000;

    /**
     * 用來檢測鏈接是否有效的sql,要求是一個查詢語句,經常使用select
     * 'x'。若是validationQuery爲null,testOnBorrow、testOnReturn、testWhileIdle都不會其做用。
     */
    private String validationQuery = "SELECT USER()";

    /**
     * 建議配置爲true,不影響性能,而且保證安全性。申請鏈接的時候檢測,若是空閒時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測鏈接是否有效。
     */
    private boolean testWhileIdle = true;

    /**
     * 申請鏈接時執行validationQuery檢測鏈接是否有效,作了這個配置會下降性能。
     */
    private boolean testOnBorrow = false;

    /**
     * 歸還鏈接時執行validationQuery檢測鏈接是否有效,作了這個配置會下降性能。
     */
    private boolean testOnReturn = false;

    /**
     * 屬性類型是字符串,經過別名的方式配置擴展插件,經常使用的插件有: 監控統計用的filter:stat 日誌用的filter:log4j
     * 防護sql注入的filter:wall
     */
    private String filters = "mergeStat,config,wall";

    private String connectionProperties;

    /**
     * 白名單
     */
    private String allow;

    /**
     * 黑名單
     */
    private String deny;

    private String username = "admin";

    private String password = "admin";
    
    省略 get set
}

配置數據源 one

@Configuration
@EnableTransactionManagement
public class DBOneConfiguration extends AbstractDruidDBConfig {

    @Value("${ymq.one.datasource.url}")
    private String url;

    @Value("${ymq.one.datasource.username}")
    private String username;

    @Value("${ymq.one.datasource.password}")
    private String password;

    // 註冊 datasourceOne
    @Bean(name = "datasourceOne", initMethod = "init", destroyMethod = "close")
    public DruidDataSource dataSource() {
        return super.createDataSource(url, username, password);
    }

    @Bean(name = "sqlSessionFactorYmqOne")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        return super.sqlSessionFactory(dataSource());
    }

    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        return new DataSourceTransactionManager(dataSource());
    }
}

配置數據源 two

@Configuration
@EnableTransactionManagement
public class DBOneConfiguration extends AbstractDruidDBConfig {

    @Value("${ymq.one.datasource.url}")
    private String url;

    @Value("${ymq.one.datasource.username}")
    private String username;

    @Value("${ymq.one.datasource.password}")
    private String password;

    // 註冊 datasourceOne
    @Bean(name = "datasourceOne", initMethod = "init", destroyMethod = "close")
    public DruidDataSource dataSource() {
        return super.createDataSource(url, username, password);
    }

    @Bean(name = "sqlSessionFactorYmqOne")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        return super.sqlSessionFactory(dataSource());
    }

    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        return new DataSourceTransactionManager(dataSource());
    }
}

BaseDao one

@Repository
public class YmqOneBaseDao extends BaseDao {

    @Resource
    public void setSqlSessionFactorYmqOne(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }
}

BaseDao two

@Repository
public class YmqTwoBaseDao extends BaseDao {

    @Resource
    public void setSqlSessionFactorYmqTwo(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }
}

測試 Controller

@RestController
public class IndexController {

    private static final Logger LOG = LoggerFactory.getLogger(IndexController.class);

    @Autowired
    private YmqOneBaseDao ymqOneBaseDao;

    @Autowired
    private YmqTwoBaseDao ymqTwoBaseDao;

    @RequestMapping("/")
    public String index() throws Exception {

        List<TestOnePo> testOnePoList = null;

        testOnePoList = ymqOneBaseDao.selectList(new TestOnePo());
        for (TestOnePo item : testOnePoList) {
            LOG.info("數據源 ymqOneBaseDao :查詢結果:{}", JSONObject.toJSONString(item));
        }

        List<TestTwoPo> testTwoPoList = null;

        testTwoPoList = ymqTwoBaseDao.selectList(new TestTwoPo());

        for (TestTwoPo item : testTwoPoList) {
            LOG.info("數據源 ymqTwoBaseDao:查詢結果:{}", JSONObject.toJSONString(item));
        }

        String onePoList = JSONObject.toJSONString(testOnePoList);
        String twoPoList = JSONObject.toJSONString(testTwoPoList);

        return "數據源 ymqOneBaseDao :查詢結果:" + onePoList + "<br/> 數據源 ymqTwoBaseDao :查詢結果:" + twoPoList;
    }
}

參數配置

application.propertiessql

#############SERVER CONFIG############
spring.application.name=ymq-mybatis-spring-boot

#數據源 one
ymq.one.datasource.url=jdbc:mysql://10.4.82.6:3306/ymq_one?useUnicode=true&characterEncoding=UTF-8
ymq.one.datasource.username=root
ymq.one.datasource.password=123456

#數據源 two
ymq.two.datasource.url=jdbc:mysql://10.4.82.6:3306/ymq_two?useUnicode=true&characterEncoding=UTF-8
ymq.two.datasource.username=root
ymq.two.datasource.password=123456

server.port=80
server.tomcat.max-threads=1000
server.tomcat.max-connections=2000

啓動服務

@SpringBootApplication
@ComponentScan(value = {"io.ymq.mybatis"})
public class Startup {

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

在頁面上輸入 http://localhost/ 能夠看到 Controller 執行狀況:數據庫

數據源 ymqOneBaseDao :查詢結果:[{"id":1,"name":"測試","remark":"這是測試 ymq_one 數據庫"}]
數據源 ymqTwoBaseDao :查詢結果:[{"id":1,"name":"測試","remark":"這是測試 ymq_two 數據庫"}]

在頁面上輸入 http://localhost/druid/ 能夠看到監控到的sql語句執行狀況:segmentfault

 druid 監控

代碼我已放到 Github ,導入spring-boot-mybatis 項目 tomcat

github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-mybatis

Contact

  • 做者:鵬磊
  • 出處:http://www.ymq.io
  • Email:admin@souyunku.com
  • 版權歸做者全部,轉載請註明出處
  • Wechat:關注公衆號,搜雲庫,專一於開發技術的研究與知識分享

關注公衆號-搜雲庫

相關文章
相關標籤/搜索