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这样就可以动态配置了。实现如下

@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中关闭(这里的配置优先级最高)。至此技术分享结束。

                   心得有二,第一看懂源码很重要,第二和同事聊聊可能会有心得思路,到了最后一步真不知道怎么弄了,问了下同事,豁然开朗,还是年轻、年轻.......

你可能感兴趣的:(sspringboot新发现)