本文是一篇问题解决经验分享的文章。因为在网上没有搜到相关的介绍文章,而在遇到这个问题的解决过程中,犯过一些想当然的错误,所以记录在此,希望能够对后面遇到此问题的朋友有所帮助
参考官方文档进行了相关配置。
https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.java
- 通过MybatisProperties 将application.yml文件中mybatis相关配置映射到properties文件中
- 通过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.TGroupStatement 3.tryOnDataSource(TGroupStatement.java:439)atcom.taobao.tddl.group.jdbc.TGroupStatement 3. t r y O n D a t a S o u r c e ( T G r o u p S t a t e m e n t . j a v a : 439 ) a t c o m . t a o b a o . t d d l . g r o u p . j d b c . T G r o u p S t a t e m e n t 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();
}
扫面二维码,了解更多