springboot添加多數據源鏈接池並配置Mybatishtml
轉載請註明出處:http://www.javashuo.com/article/p-vfpnmrep-e.htmljava
May 12, 2018 星期六,那是個晴天,天湛藍湛藍的很是乾淨,彷彿飄過一粒塵埃也能看得清清楚楚,而後就發生了些事情。。。很傷心很難過,至今也沒能抹去,欸,我是怎樣一步步把本身變成這個樣子呢。mysql
難過的事情總會在縈繞好久,罷了,這裏仍是不回憶了,就這樣吧。git
首先我說說此次配置多數據源的緣由吧:緣由大體有二:github
一是咱們的線上的有兩大業務系統雲像系統和線上交易系統,這兩個系統的分別使用各自的mysql實例,交合業務的狀況下目前經過定時腳本作數據更新和同步,遂在開發新的業務模塊的時候就想到了將springboot配置兩個數據源(mysql和mysql)spring
二是最近在改造數據庫日誌表的時候發現mysql的優化捉襟見肘,遂就想到了換數據庫,換個我我的研究了許久的PostgreSQL,老大一開始不怎麼樂意這麼幹,可是看我又研究了這麼久,性能也確實較mysql高許多,再加上公司技術團隊並非很大的狀況下(主要是業務量上去了數據庫性能跟不上,也沒有獨立的DBA來維護和調優Mysql),就給了我一週的時間研究數據庫(下次具體聊),故就涉及到兩個數據源(mysql和PostgreSQL)的問題。sql
嗯,對於以上兩個問題,我嘗試了差別化的解決方式,對於mysl和mysql數據源我選擇的是 阿里Druid+TK.Mybatis的解決方式,對於mysql和PG數據源我選擇的是Hikari+TK.Mybatis的解決方式.這兩種方式在實際配置中是有些許差別的,這裏我略去不講,只講第二種,首先羅列下這其中碰到的問題:數據庫
A>DataSource和SessionFactory引用指定注入問題。apache
B>Hikari數據源配置參數名稱差別問題。springboot
C>Springboot init時配置類前後順序的問題
D>多數據源下Mybatis Mapper類重複問題
我先講講我大體的配置過程吧,首先新創建兩個配置類,以隔離開(剛在一個包 中不隔離開也能夠):
而後在兩個包中分別新建兩個配置類,一個是MyBatis配置類和數據源、session工廠配置類,我這裏是這樣子:
這時候,我先展現下數據源配置類:
1 package **.task.config.mysql; 2
3
4 import com.github.pagehelper.PageHelper; 5 import com.zaxxer.hikari.HikariConfig; 6 import com.zaxxer.hikari.HikariDataSource; 7 import org.apache.commons.lang3.StringUtils; 8 import org.apache.ibatis.plugin.Interceptor; 9 import org.apache.ibatis.session.SqlSessionFactory; 10 import org.mybatis.spring.SqlSessionFactoryBean; 11 import org.mybatis.spring.SqlSessionTemplate; 12 import org.springframework.beans.factory.annotation.Qualifier; 13 import org.springframework.beans.factory.annotation.Value; 14 import org.springframework.boot.context.properties.ConfigurationProperties; 15 import org.springframework.context.annotation.Bean; 16 import org.springframework.context.annotation.Configuration; 17 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 18 import org.springframework.core.io.support.ResourcePatternResolver; 19 import org.springframework.jdbc.datasource.DataSourceTransactionManager; 20 import org.springframework.transaction.annotation.EnableTransactionManagement; 21
22 import javax.sql.DataSource; 23 import java.sql.SQLException; 24 import java.util.Properties; 25
26 /**
27 * mybatis 配置數據源類 28 * 29 * @author
30 * @date 2016年12月15日 31 * @since 1.7 32 */
33 @Configuration("mysqlCfg") 34 @EnableTransactionManagement 35 @ConfigurationProperties(prefix = "spring.db_mysql") //引用配置文件參數前綴 36 public class MybatisConfiguration extends HikariConfig { 37 @Value("${mybatis.mysql.xmlLocation}") 38 private String xmlLocation; 39
40 private String typeAliasesPackage; 41 //配置數據源
42 @Bean("mysqlDataSource") 43 public DataSource dataSource(){ 44 /*
45 HikariDataSource ds=HikariDataSource(); 46 ds.setJdbcUrl(); 47 ds.setConnectionTimeout(); 48 */
49 return new HikariDataSource(this); 50 } 51 //配置Session工廠
52 @Bean(name = "mysqlSqlSessionFactory") 53 public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("mysqlDataSource")DataSource dataSource) { 54 SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); 55 bean.setDataSource(dataSource); 56 if(StringUtils.isNotBlank(typeAliasesPackage)){ 57 bean.setTypeAliasesPackage(typeAliasesPackage); 58 } 59 //分頁插件
60 PageHelper pageHelper = new PageHelper(); 61 Properties properties = new Properties(); 62 properties.setProperty("reasonable", "true"); 63 properties.setProperty("supportMethodsArguments", "true"); 64 properties.setProperty("returnPageInfo", "check"); 65 properties.setProperty("params", "count=countSql"); 66 pageHelper.setProperties(properties); 67 //添加XML目錄
68 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 69 Interceptor[] plugins = new Interceptor[]{pageHelper}; 70 bean.setPlugins(plugins); 71 try { 72
73 bean.setMapperLocations(resolver.getResources(xmlLocation)); 74 return bean.getObject(); 75 } catch (Exception e) { 76 e.printStackTrace(); 77 throw new RuntimeException(e); 78 } 79 } 80 //mybatis會用到的SqlSession模板
81 @Bean 82 public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { 83 return new SqlSessionTemplate(sqlSessionFactory); 84 } 85 //數據源事物配置
86 @Bean 87 public DataSourceTransactionManager transactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) { 88 return new DataSourceTransactionManager(dataSource); 89 } 90
91 }
在這裏須要說明的是我經過繼承HikariConfig來配置數據源以及Session工廠,配置DataSource和Session工廠的時候須要使用指定註解名稱,在這裏是「mysqlDataSource「和」mysqlSqlSessionFactory「,若是項目只有一個數據源的話大可沒必要寫這個的,另外須要特別注意的是在配置session工廠必定要在形式參數前使用@Qualifier註解引用指定的數據源,同時SqlSession模板和事物也須要經過@Qualifier註解指定session工廠和數據源,這裏這樣作的緣由是爲了解決多數據源配置引用不明的問題。
OK,數據源配置完成了,如今將配置第二個配置類Mybatis配置類,如下是具體配置內容:
1 package **.task.config.mysql; 2 3 import org.springframework.boot.autoconfigure.AutoConfigureAfter; 4 import org.springframework.boot.bind.RelaxedPropertyResolver; 5 import org.springframework.context.EnvironmentAware; 6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Configuration; 8 import org.springframework.core.env.Environment; 9 import tk.mybatis.spring.mapper.MapperScannerConfigurer; 10 11 /** 12 * mybatis mapper 掃描配置類 13 * 14 * @author 15 * @date 2018年05月15日 16 */ 17 @Configuration("mysqlMapper") 18 @AutoConfigureAfter(MybatisConfiguration.class)//init時指定前後順序,這裏是數據源在mybatis以前配置 19 public class MapperConfiguration implements EnvironmentAware { 20 21 private RelaxedPropertyResolver propertyResolver; 22 23 private String basePackage; 24 //這裏爲mybatis配置指定session工廠和Dao類基礎包路徑 25 @Bean("mysqlMapperScannerConfigurer") 26 public MapperScannerConfigurer mapperScannerConfigurer(Environment environment){ 27 28 MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); 29 mapperScannerConfigurer.setSqlSessionFactoryBeanName("mysqlSqlSessionFactory"); 30 mapperScannerConfigurer.setBasePackage(basePackage); 31 return mapperScannerConfigurer; 32 } 33 34 //設置環境變量(引用配置文件中的) 35 @Override 36 public void setEnvironment(Environment environment) { 37 this.propertyResolver = new RelaxedPropertyResolver(environment, null); 38 this.basePackage = propertyResolver.getProperty("mybatis.mysql.basepackage"); 39 } 40 }
配置Mybaits的時候須要將數據源配置置於以後配置,這裏經過註解@AutoConfigureAfter來指定數據源配置類,在配置Mybatis引用的Session工廠時也要指定爲數據源配置類中的sqlSession工廠,同時也須要指定生成的Mapper的包名,這個包的路徑這裏我寫在application.yml的配置文件中。
配置類已經寫完,如今最後一步了,在配置文件中指定配置類所引用的配置參數,大體是這樣子:
spring: application: name: **-task jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 default-property-inclusion: non_null db_mysql: name: DEV_MYSQL #LOCAL jdbc-url: jdbc:mysql://${MYSQL_HOST:192.168.10.141}:${MYSQL_PORT:3306}/p2p?useUnicode=true&characterEncoding=UTF8 driver-class-name: com.mysql.jdbc.Driver username: p2p password: p2p # Hikari connection pool type: com.zaxxer.hikari.HikariDataSource minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: DatebookHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1 validation-timeout: 10000 db_pg: name: DEV_PG # JDBC config jdbc-url: jdbc:postgresql://192.168.10.141:5432/log driver-class-name: org.postgresql.Driver username: log password: log # Hikari connection pool type: com.zaxxer.hikari.HikariDataSource minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: DatebookHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1 validation-timeout: 10000
以上配置文件中主要展現了數據源的一些配置(注意db_mysql和db_pg這兩項),這裏須要特別注意的是在Hikari數據源的配置參數中沒有url和driverClass,只有jdbc-url 和 driver-class-name這兩個,其它的配置配置參數名稱與c3p0和Druid的無異,具體的鏈接池大小須要根據實際的項目和數據庫服務器的硬件參數來配置,這裏我只給出常見配置。
哦,對了,還須要在配置文件中追加Mybatis的配置參數,具體是這樣:
1 mybatis: 2 mysql: 3 basepackage: **.task.mapper.mysql 4 xmlLocation: classpath:mapper/mysql/*.xml 5 pg: 6 basepackage: **.task.mapper.pg 7 xmlLocation: classpath:mapper/pg/*.xml
Mybatis的配置完成了,對於PostgreSQL的配置只須要注意響應的配置別名便可(好比數據源、session工廠、SqlSession工廠等等)
本節所講的配置貌似已經完成,可是這裏我順帶講一下我在性能測試的時候所碰見的兩個TK.mybatis這個插件的問題(原生mybatis也可能存在):
A>對於兩個庫中存在同名的Mapper名字,在@Autowired使用時會產生衝突
B>持久化須要返回主鍵時對於mysql和PG兩中數據庫的處理方式存在差別
對於以上第一個問題(多數據源Mapper衝突),我給出的解決方式是在生成的Mapper類中指定衝突的那個Mapper的Service別名,這樣:
1 package **.task.mapper.pg; 2 3 import com.github.carvechris.security.task.entity.pg.TestEmp; 4 import org.springframework.stereotype.Service; 5 import tk.mybatis.mapper.common.Mapper; 6 7 @Service("pgTestEmpMapper")//這裏指定別名 8 public interface TestEmpMapper extends Mapper<TestEmp> { 9 }
這個Dao在使用的時候須要使用@Resource註解來指定的Dao類:
1 @Autowired 2 @Resource(name = "pgTestEmpMapper") 3 private **.task.mapper.pg.TestEmpMapper pgEmpMapper;
對於以上第二個問題(持久化返回主鍵問題),mysql和pg的處理方式不一樣,具體爲:
對於mysql:須要在實體類中指定主鍵的生成方式,便可在調用insert方法時返回生成的主鍵:
/** * 表ID */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)//設置爲主鍵自增以回寫主鍵 private Integer id;
以上的主鍵策略能夠是主鍵表,也能夠是UUID的方式,根據項目實際需求而定。
對於PG:首先須要在實體類的主鍵中這樣聲明:
/** * 表ID */ @Id @Column(insertable=false)//指定主鍵爲數據庫生成(同時須要在DB中將ID聲明爲serial類型) private Long id;
再在Dao(生成的Mapper類中)聲明一個獨立的查入方法:
1 package **.task.mapper.pg; 2 3 import **.task.entity.pg.ZwPlBalancequery; 4 import org.apache.ibatis.annotations.InsertProvider; 5 import org.a2018-06-16pache.ibatis.annotations.Options; 6 import org.apache.ibatis.annotations.Select; 7 import tk.mybatis.mapper.common.Mapper; 8 import tk.mybatis.mapper.provider.base.BaseInsertProvider; 9 10 public interface ZwPlBalancequeryMapper extends Mapper<ZwPlBalancequery> { 11 //須要須要獨立聲明插入方法以返回插入記錄的ID 12 @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id") 13 @InsertProvider(type = BaseInsertProvider.class, method = "dynamicSQL") 14 int insertWBack(ZwPlBalancequery record); 15 }
以上插入方法(insertWBack)中的註解是將id的生成方式改成數據庫生成,至此,完美解決持久化返回記錄ID問題。
如今是 2018-06-16 17:40:42 ,後天就是端午節了,預祝各位節日快樂!