Springboot 配置多資料來源Mybatis的UnderScore不生效

方丈的寺院發表於2018-04-27

摘要

本文是一篇問題解決經驗分享的文章。因為在網上沒有搜到相關的介紹文章,而在遇到這個問題的解決過程中,犯過一些想當然的錯誤,所以記錄在此,希望能夠對後面遇到此問題的朋友有所幫助

問題

參考官方文件進行了相關配置。

https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.java

  1. 通過MybatisProperties 將application.yml檔案中mybatis相關配置對映到properties檔案中
  2. 通過MybatisAutoConfiguration注入SqlSessionFactory的Bean到容器中

通過這個配置,就可以在程式碼中開心的通過mybatis的運算元據庫了。

但是這種方式只能配置一種資料來源,像下面這樣再配置一個

  @Bean(name = "siteASqlSessionFactory")
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);
    if (StringUtils.hasText(this.properties.getConfigLocation())) {
      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }
    applyConfiguration(factory);
    if (this.properties.getConfigurationProperties() != null) {
      factory.setConfigurationProperties(this.properties.getConfigurationProperties());
    }
    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }
    if (this.databaseIdProvider != null) {
      factory.setDatabaseIdProvider(this.databaseIdProvider);
    }
    if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
      factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
    }
    if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
      factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
    }
    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }

    return factory.getObject();
  }

問題1:如果再配置一個,像上面那樣,會發現報錯,找不到對應的表schema,sql執行失敗。

SprintBootVFS
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table ‘site.post’ doesn’t exist
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4098)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4030)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2671)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2621)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1557)
at com.alibaba.druid.pool.DruidPooledStatement.executeQuery(DruidPooledStatement.java:140)
at com.taobao.tddl.atom.jdbc.TStatementWrapper.executeQuery(TStatementWrapper.java:260)
at com.taobao.tddl.group.jdbc.TGroupStatement.executeQueryOnConnection(TGroupStatement.java:426)
at com.taobao.tddl.group.jdbc.TGroupStatement3.tryOnDataSource(TGroupStatement.java:439)atcom.taobao.tddl.group.jdbc.TGroupStatement

3.tryOnDataSource(TGroupStatement.java:439) at com.taobao.tddl.group.jdbc.TGroupStatement
3.tryOnDataSource(TGroupStatement.java:430)
at

然後就改成下面這樣,另外一個資料來源改成這樣的配置

@Bean(name = "siteASqlSessionFactory")
    public SqlSessionFactory siteASqlSessionFactory(@Qualifier("siteADataSource") DataSource siteATaskDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(siteATaskDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(SiteADataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }

問題2:問題就遇到了,如題所說,mapUnderScoreToCamelCase配置不生效,
一開始沒理解為什麼不生效,明明application.yml中已經配置了。但是分析了一下就知道,因為mapUnderScoreToCamelCase是Configuration的一個屬性,之前習慣了這種配置,框架幫忙做了,不瞭解其原理,在這邊SqlSessionFactory中根本沒有配置configuration物件,當然不生效。

所以現在瞭解了問題,mapUnderScoreToCamelCase是Configuration的一個屬性,Configuration需要注入到SqlSesssionFactory中。然後配置多個資料來源後,為什麼會找不到第二個資料來源的schema了。通過debug發現,

Configuration類中有一個變數Environment,

protected Environment environment;

Environment中有個DataSource物件,這個之前我們介紹過,是資料庫連線物件,所以問題比較清楚了,當注入第一個sqlSessionFactory後資料庫連線時正常的,但是當注入第二個資料來源的sqlSessionFactory,由於Configuration.Environment.DataSource已經配置了第一個資料來源的資訊,所以在web容器啟動後,進行資料庫操作時,會報找不到資料庫schema

public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;
  }

解決

找到root cause後,解決就簡單了。配置兩個Configuration就好了
資料來源1

  @Bean(name = "siteASqlSessionFactory")
    public SqlSessionFactory siteASqlSessionFactory(@Qualifier("siteADataSource") DataSource siteADataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(siteADataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(siteADataSourceConfig.MAPPER_LOCATION));
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session
                .Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        sessionFactory.setConfiguration(configuration);
        return sessionFactory.getObject();
    }

資料來源2

```
  @Bean(name = "siteBSqlSessionFactory")
    public SqlSessionFactory siteASqlSessionFactory(@Qualifier("siteBDataSource") DataSource siteADataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(siteBDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(siteBDataSourceConfig.MAPPER_LOCATION));
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session
                .Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        sessionFactory.setConfiguration(configuration);
        return sessionFactory.getObject();
    }

掃面二維碼,瞭解更多

這裡寫圖片描述

相關文章