1. 程式人生 > >springboot 整合 pagehelper + tk-mybatis 多資料來源問題

springboot 整合 pagehelper + tk-mybatis 多資料來源問題

             閒暇之餘,寫點最近的收穫,寫一點心得,便於以後參考方便,另外可以幫助有這樣需求的人少走彎路。

          整合多個數據源,很多部落格會提到springboot整合jdbcTemplete為例子,網上有很多,今天主要推薦的是整合 pagehelper + tk-mybatis 多資料來源問題。

              其實很簡單,我的整合思路分為以下幾個步驟。

              一、建立java配置類,這個配置類裡面主要內容有dataSource、sqlSessionFactory、transactionManager、sqlSessionTemplete、具體實現如下:

@Configuration
@MapperScan(/*basePackages = "com.batman.bysj.common.dao.mapper",*/
sqlSessionTemplateRef = "bysjSqlSessionTemplate", basePackageClasses = TestMapper.class)
@EnableConfigurationProperties(value = BysjDruidDBProperties.class)
public class BysjDruidDBAutoConfiguration {
private Logger logger 
= LoggerFactory.getLogger(BysjDruidDBAutoConfiguration.class); private final BysjDruidDBProperties bysjDruidDBProperties; @Autowired public BysjDruidDBAutoConfiguration(BysjDruidDBProperties bysjDruidDBProperties) { this.bysjDruidDBProperties = bysjDruidDBProperties; } @Bean(name = "bysjDataSource"
) @Primary //在同樣的DataSource中,首先使用被標註的DataSource public DataSource bysjDataSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(bysjDruidDBProperties.getUrl()); datasource.setUsername(bysjDruidDBProperties.getUsername()); datasource.setPassword(bysjDruidDBProperties.getPassword()); datasource.setDriverClassName(bysjDruidDBProperties.getDriverClassName()); //configuration datasource.setInitialSize(bysjDruidDBProperties.getInitialSize()); datasource.setMinIdle(bysjDruidDBProperties.getMinIdle()); datasource.setMaxActive(bysjDruidDBProperties.getMaxActive()); datasource.setMaxWait(bysjDruidDBProperties.getMaxWait() == 0 ? bysjDruidDBProperties.getMaxWait() : 6000); datasource.setTimeBetweenEvictionRunsMillis(bysjDruidDBProperties.getTimeBetweenEvictionRunsMillis()); datasource.setMinEvictableIdleTimeMillis(bysjDruidDBProperties.getMinEvictableIdleTimeMillis()); datasource.setValidationQuery(bysjDruidDBProperties.getValidationQuery()); datasource.setTestWhileIdle(bysjDruidDBProperties.isTestWhileIdle()); datasource.setTestOnBorrow(bysjDruidDBProperties.isTestOnBorrow()); datasource.setTestOnReturn(bysjDruidDBProperties.isTestOnReturn()); datasource.setPoolPreparedStatements(bysjDruidDBProperties.isPoolPreparedStatements()); datasource.setMaxPoolPreparedStatementPerConnectionSize(bysjDruidDBProperties.getMaxPoolPreparedStatementPerConnectionSize()); try { datasource.setFilters(bysjDruidDBProperties.getFilters()); } catch (SQLException e) { logger.error("druid configuration initialization filter", e); } datasource.setConnectionProperties(bysjDruidDBProperties.getConnectionProperties()); return datasource; } @Bean(name = "bysjSqlSessionFactory") @Primary public SqlSessionFactory bysjSqlSessionFactory(@Qualifier("bysjDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources( "classpath:mapper/bysj/*.xml")); return bean.getObject(); } @Bean(name = "bysjTransactionManager") @Primary public DataSourceTransactionManager bysjTransactionManager(@Qualifier("bysjDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "bysjSqlSessionTemplate") @Primary public SqlSessionTemplate bysjSqlSessionTemplate(@Qualifier("bysjSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }

          需要注意的是需要標記@Primary註解,spring需要知道當前主要載入哪一個,上面的註解有MapperScan指定mybatis掃描的mapper檔案位置以及所需要sqlSessionFactory的id,事務管理器可以配也可以不配(需要事務就配上),sqlSessionTemplete也可配可不配(可以從sqlSessionFactory中獲取)。@EnableConfigurationProperties這樣就可以springboot啟動時自動掃描了,另外需要在spring.factories中配置,具體這點會在寫下部落格說明springboot中的自動配置是怎麼實現的。  

        二、接下來給出properties檔案。

@ConfigurationProperties(prefix = "spring.datasource")
public class BysjDruidDBProperties {
private String url;
private String username;
private String password;
private String driverClassName;
private int initialSize;
private int minIdle;
private int maxActive;
private long maxWait;
private long timeBetweenEvictionRunsMillis;
private long minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
private String filters;
private String connectionProperties;
public String getUrl() {
return url;
    }
public void setUrl(String url) {
this.url = url;
    }
public String getUsername() {
return username;
    }
public void setUsername(String username) {
this.username = username;
    }
public String getPassword() {
return password;
    }
public void setPassword(String password) {
this.password = password;
    }
public String getDriverClassName() {
return driverClassName;
    }
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
    }
public int getInitialSize() {
return initialSize;
    }
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
    }
public int getMinIdle() {
return minIdle;
    }
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
    }
public int getMaxActive() {
return maxActive;
    }
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
    }
public long getMaxWait() {
return maxWait;
    }
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
    }
public long getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
    }
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }
public long getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
    }
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }
public String getValidationQuery() {
return validationQuery;
    }
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
    }
public boolean isTestWhileIdle() {
return testWhileIdle;
    }
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
    }
public boolean isTestOnBorrow() {
return testOnBorrow;
    }
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
    }
public boolean isTestOnReturn() {
return testOnReturn;
    }
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
    }
public boolean isPoolPreparedStatements() {
return poolPreparedStatements;
    }
public void setPoolPreparedStatements(boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
    }
public int getMaxPoolPreparedStatementPerConnectionSize() {
return maxPoolPreparedStatementPerConnectionSize;
    }
public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
    }
public String getFilters() {
return filters;
    }
public void setFilters(String filters) {
this.filters = filters;
    }
public String getConnectionProperties() {
return connectionProperties;
    }
public void setConnectionProperties(String connectionProperties) {
this.connectionProperties = connectionProperties;
    }
}

            三、接下來就是配置application.yml檔案了,和平常配置資料庫一樣按照提示即可,網上可以搜到很多。

            四、要配置另一個數據源就在走一遍一、二、三,不過要注意,給的bean的名稱不能重複,你懂得。

            五、多謝讀者能看到最後,最大的坑就在於通用mapper,當我們所有的資料來源都配置好了之後,當我們呼叫通用的時候會出現sqlSessionFactory只會是primary的那個,另一個不起作用,這是因為MapperAutoConfiguration中只配置了一個sqlSesisonFactory,這樣就會出現自動切換資料來源,需要新增一個List<SqlSessionFactory>這樣就可以動態配置了。實現如下

@Configuration
@ConditionalOnBean(SqlSessionFactory.class)
@EnableConfigurationProperties(MapperProperties.class)
@AutoConfigureAfter(MybatisAutoConfiguration.class)
public class CustomizedMapperAutoConfiguration {
private final List<SqlSessionFactory> sqlSessionFactoryList;
@Autowired
private       MapperProperties  properties;
public CustomizedMapperAutoConfiguration(List<SqlSessionFactory> sqlSessionFactoryList) {
this.sqlSessionFactoryList = sqlSessionFactoryList;
    }
@PostConstruct
public void addPageInterceptor() {
MapperHelper mapperHelper = new MapperHelper();
mapperHelper.setConfig(properties);
if (properties.getMappers().size() > 0) {
for (Class mapper : properties.getMappers()) {
mapperHelper.registerMapper(mapper);
            }
        } else {
mapperHelper.registerMapper(Mapper.class);
        }
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
mapperHelper.processConfiguration(sqlSessionFactory.getConfiguration());
        }
    }
}
                此外,我們需要把那個預設的MapperAutoConfiguration關閉,在springboot啟動中的@SpringBootApplication中關閉(這裡的配置優先順序最高)。至此技術分享結束。

                   心得有二,第一看懂原始碼很重要,第二和同事聊聊可能會有心得思路,到了最後一步真不知道怎麼弄了,問了下同事,豁然開朗,還是年輕、年輕.......