Spring Boot 使用HikariCP和MyBatis配置多數據源支持

Spring Boot 2 開始,默認的數據庫連接池是HikariCP,一般沒有特殊定製化的需求,HikariCP都是推薦的數據庫連接池組件。MyBatis也是現在使用較多的ORM框架,一般都是選擇使用它。

多數據源的配置需求很容易遇到,這方面的文檔官方並沒有提供直接的example支持,大部分情況下,確實單數據源就已經滿足需求。

1、啟動排除自動配置類

也可以不操作,Spring Boot 默認的Bean處理,會根據實際的Bean來依賴實例化特定的類,如果沒有足夠的條件,框架也不是無窮無盡的去實例化它認為需要的實例。

import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
@SpringBootApplication(
exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class,
MybatisAutoConfiguration.class
}
)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

2、配置文件

# 數據源配置
datasource:
a:

jdbc-url: jdbc:mysql://ip:port/dbName?characterEncoding=utf8&useSSL=true
username: username
password: .....
# 以下為 HikariCP 連接池信息
pool-name: HikariPool-a
minimum-idle: 4
maximum-pool-size: 10
b:
jdbc-url: jdbc:mysql://ip:port/dbName?characterEncoding=utf8&useSSL=true
username: userName
password: ......
pool-name: HikariPool-b
minimum-idle: 2
maximum-pool-size: 5

3、數據源配置類

數據源配置類需要,每個數據源要有單獨的配置類,雖然內容基本上是一樣的,但是掃描包的路徑是需要明確分開的。

這裡面有個坑,說實話我不知道是網上的文章太久了,還是大家的版本不一致,導致一些解決方案總是失效的。比如下面這個配置:

@Bean("aSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("aDataSource") DataSource dataSource) throws Exception {
// 重要: 注意設置的順序, SqlSessionFactoryBean 設置屬性後再獲取 getObject, 否則不生效
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// 如果有 *Mapper.xml 接口實現需要配置, 請在該處配置
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappers/a/*Mapper.xml"));
// 支持自動轉化駝峰
bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);

return bean.getObject();
}

你注意到 bean.getObject()這行了嗎,如果這之後設置掃描xml接口實現文件,那將是不生效的,但我在網上搜索到的答案中,都是在這一行之後掃描。我在這裡調試了很久,就差沒看MyBatis的源代碼了。後來只能打印配置的內容,才發現這個順序問題。我不知道寫這個的人自己有沒有調試過,還是知道有這麼個配置項,具體生效不生效,需要使用者自行去確定。

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.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* a 數據源
*/
@Configuration
@MapperScan(
basePackages = "com.....",
sqlSessionTemplateRef = "ASqlSessionTemplate"
)
public class ADatasourceConfig {
/**
* a 數據源
*
* @return 默認指定的連接池為框架默認的 {@link com.zaxxer.hikari.HikariDataSource}

*/
@Bean("aDataSource")
@ConfigurationProperties(prefix = "datasource.miio")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean("aSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("aDataSource") DataSource dataSource) throws Exception {
// 重要: 注意設置的順序, SqlSessionFactoryBean 設置屬性後再獲取 getObject, 否則不生效
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// 如果有 *Mapper.xml 接口實現需要配置, 請在該處配置
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappers/a/*Mapper.xml"));
// 支持自動轉化駝峰
bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return bean.getObject();
}
/**
* 使用Spring聲明式事務時需要明確指定事務管理器
*
* @param dataSource 對應的數據源
* @return 需要使用者明確引用的事務管理器
*/
@Bean("aDataSourceTransactionManager")
public PlatformTransactionManager platformTransactionManager(@Qualifier("aDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("aSqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("aSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
/**
* jdbcTemplate 數據庫操作模板, 可單獨使用操作數據庫
*
* @param dataSource a 數據源
* @return a 數據操作模板
*/
@Bean("aJdbcTemplate")
public JdbcTemplate jdbcTemplate(@Qualifier("aDataSource") DataSource dataSource) {

return new JdbcTemplate(dataSource);
}
}

4、Java註解和xml實現

如果使用Java註解去編寫SQL,那其實無需提供任何的xml接口實現文件。對於大部分的SQL來說,確實一個@Select("")註解比什麼都方便,也不需要過多的配置。但是@Update("")就沒那麼容易了,比如我的Where條件是不固定的,有的值可能並不存在,或者Set的內容也是動態的。我並不想為每種情形編寫一個@Update方法,註解實現就顯得有點囉嗦和不那麼容易了。

這時候xml配置的優勢就體現出來,xml提供的特定格式巧妙的解決了很多問題,可以避開復雜的SQL語法,比如CASE WHEN條件等等,就像下面這個,我的where有兩個條件,而且後一個可能為空的時候,就特別的直接和簡單:


br> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper>

rid,
refund_id as "refundId",
oid,
uid,
pid,
status,

`count`


<select>
SELECT
<include>
FROM shop_refound_order
WHERE oid = #{orderId}

AND pid IN
<foreach>
#{item}
/<foreach>

/<select>
/<mapper>

你看訂單條件肯定存在,但是後一個IN條件就可能為空,這時候用xml來編寫就變得極其容易了。

實際項目中,一般統一為一種方式,也可以兩種並用,為了減輕複雜性,一般是一個項目保持一種風格,只要是解決了項目的問題,其實選擇哪種意義不大。


分享到:


相關文章: