1. 程式人生 > >springboot添加多數據源連接池並配置Mybatis

springboot添加多數據源連接池並配置Mybatis

是個 -name 個數 數據庫日誌 發生 uri -i esql 開始

springboot添加多數據源連接池並配置Mybatis

轉載請註明出處:https://www.cnblogs.com/funnyzpc/p/9190226.html

May 12, 2018 星期六,那是個晴天,天湛藍湛藍的非常幹凈,仿佛飄過一粒塵埃也能看得清清楚楚,然後就發生了些事情。。。很傷心很難過,至今也沒能抹去,欸,我是怎樣一步步把自己變成這個樣子呢。

難過的事情總會在縈繞很久,罷了,這裏還是不回憶了,就這樣吧。

首先我說說這次配置多數據源的原因吧:原因大致有二:

一是我們的線上的有兩大業務系統雲像系統和線上交易系統,這兩個系統的分別使用各自的mysql實例,交合業務的情況下目前通過定時腳本做數據更新和同步,遂在開發新的業務模塊的時候就想到了將springboot配置兩個數據源(mysql和mysql)

二是最近在改造數據庫日誌表的時候發現mysql的優化捉襟見肘,遂就想到了換數據庫,換個我個人研究了許久的PostgreSQL,老大一開始不怎麽樂意這麽幹,但是看我又研究了這麽久,性能也確實較mysql高許多,再加上公司技術團隊並不是很大的情況下(主要是業務量上去了數據庫性能跟不上,也沒有獨立的DBA來維護和調優Mysql),就給了我一周的時間研究數據庫(下次具體聊),故就涉及到兩個數據源(mysql和PostgreSQL)的問題。

嗯,對於以上兩個問題,我嘗試了差異化的解決方式,對於mysl和mysql數據源我選擇的是 阿裏Druid+TK.Mybatis的解決方式,對於mysql和PG數據源我選擇的是Hikari+TK.Mybatis的解決方式.這兩種方式在實際配置中是有些許差異的,這裏我略去不講,只講第二種,首先羅列下這其中碰到的問題:

   A>DataSource和SessionFactory引用指定註入問題。

   B>Hikari數據源配置參數名稱差異問題。

   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_mysqldb_pg這兩項),這裏需要特別註意的是在Hikari數據源的配置參數中沒有url和driverClass,只有jdbc-urldriver-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 ,後天就是端午節了,預祝各位節日快樂!

springboot添加多數據源連接池並配置Mybatis