代碼實現
1. 修改 application.yml配置文件,添加db_2數據庫連接
注意:配置連接兩個數據庫,url改為:jdbc-url
server:
port: 8083
servlet:
context-path: /mes
spring:
db1:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/lmes
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
db2:
datasource:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@//172.20.10.101:1521/PROD
username: apps
password: apps
type: com.alibaba.druid.pool.DruidDataSource
2. 新建config包,添加db1和db2的配置文件
- 主數據庫與從數據庫配置區別:主數據庫有
@Primary注解,從數據庫都沒有

2.1 主數據庫db1,項目啟動默認連接此數據庫:PrimaryDataSourceConfig
package com.bbzd.mes.common.datasources;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Optional;
import java.util.stream.Stream;
@Configuration
@EnableConfigurationProperties(MybatisProperties.class)
public class PrimaryDataSourceConfig {
@Autowired
private MybatisProperties properties;
@Bean(name = "db1DataSource")
@ConfigurationProperties(prefix = "spring.db1.datasource")
@Primary
public DataSource db1DataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "sqlSessionFactory")
@ConfigurationProperties(prefix = "mybatis")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTypeAliasesPackage(properties.getTypeAliasesPackage());
bean.setMapperLocations(resolveMapperLocations(properties.getMapperLocations()));
properties.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
bean.setConfiguration(properties.getConfiguration());
return bean.getObject();
}
private Resource[] resolveMapperLocations(String[] mapperLocations) {
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
return Stream.of(Optional.ofNullable(mapperLocations).orElse(new String[0]))
.flatMap(location -> Stream.of(getResources(pathMatchingResourcePatternResolver, location))).toArray(Resource[]::new);
}
private Resource[] getResources(PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver, String location) {
try {
return pathMatchingResourcePatternResolver.getResources(location);
} catch (IOException e) {
return new Resource[0];
}
}
@Bean(name = "db1TransactionManager")
@Primary
public DataSourceTransactionManager testTransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2.2 從數據庫db2:DataSource2Config
package com.bbzd.mes.common.datasources;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.bbzd.mes.oracledao",sqlSessionFactoryRef = "db2SqlSessionFactory")
public class DataSource2Config {
@Bean(name = "db2DataSource")
@ConfigurationProperties(prefix = "spring.db3.datasource")
public DataSource db3DataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db2SqlSessionFactory")
public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource datasource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(datasource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:oracle_mappers/*.xml"));
return bean.getObject();
}
@Bean(name="db2transactionManager")
public DataSourceTransactionManager transactionManagerOne(){
return new DataSourceTransactionManager(db3DataSource());
}
@Bean(name = "db2JdbcTemplate")
public JdbcTemplate jdbcTemplate(
@Qualifier("db2DataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
3. dao層
注意:主數據庫與從數據庫區別:從數據庫需要使用@Transactional 注解指向db2數據源
3.1 主數據庫db1,dao層寫法
public interface UserMapper {
boolean save(UserVo userVo);
}
3.2 從數據庫db2,dao層寫法
@Transactional(value = "db2transactionManager")
public interface UserMapper {
UserDto findById(Inter id);
}
4. resources目錄下xml注意事項
db1 和 db2 xml文件 namespace不同
-
數據庫db1,User.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.bbzd.mes.dao.UserMapper"> </mapper> -
數據庫db2,User.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.bbzd.mes.oracledao.UserMapper"> </mapper>
開發中遇到的問題
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: more than one 'primary' bean found among candidates: [db1DataSource, primaryDataSource]
多數據源報錯:No qualifying bean of type 'javax.sql.DataSource' available: more than one 'primary' bean found among candidates: [test2DataSource, test1DataSource]由於之前引入mybatis的時候引入了pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
spring會依賴spring-boot-autoconfigure這個jar包
這個jar包中 有個DataSourceAutoConfiguration 會初始化DataSourceInitializer 這個類 ,這個類有一個init方法 會去獲取DataSource(數據源)
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration
@ConditionalOnMissingBean(DataSourceInitializer.class)
protected static class DataSourceInitializerConfiguration {
@Bean
public DataSourceInitializer dataSourceInitializer() {
return new DataSourceInitializer();
}
初始化方法中 會獲取數據源 需要初始化一些ddl操作 也是就runSchemaScripts()方法 檢查初始化時是否需要執行sql script ,當你有兩個數據源的時候,程序不知道取哪一個 ,所以報錯
@PostConstruct
public void init() {
if (!this.properties.isInitialize()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
if (this.applicationContext.getBeanNamesForType(DataSource.class, false, false).length > 0) {
this.dataSource = this.applicationContext.getBean(DataSource.class);
}
if (this.dataSource == null) {
logger.debug("No DataSource found so not initializing");
return;
}
runSchemaScripts();
}
private void runSchemaScripts() {
List<Resource> scripts = getScripts(this.properties.getSchema(), "schema");
if (!scripts.isEmpty()) {
runScripts(scripts);
try {
this.applicationContext.publishEvent(new DataSourceInitializedEvent(
this.dataSource));
// The listener might not be registered yet, so don't rely on it.
if (!this.initialized) {
runDataScripts();
this.initialized = true;
}
}
catch (IllegalStateException ex) {
logger.warn("Could not send event to complete DataSource initialization ("
+ ex.getMessage() + ")");
}
}
}
解決辦法:
spring boot 啟動類加上 exclude = DataSourceAutoConfiguration.class 代表啟動項目的時候 不加載這個類
@ComponentScan(basePackages = "com.pinyu.system")
@MapperScan("com.pinyu.system.mapper")
@EnableTransactionManagement
@SpringBootApplication(exclude={
DataSourceAutoConfiguration.class,
// HibernateJpaAutoConfiguration.class, //(如果使用Hibernate時,需要加)
DataSourceTransactionManagerAutoConfiguration.class,
})
public class Application extends SpringBootServletInitializer {
}
原文鏈接:https://blog.csdn.net/github_38336924/article/details/112789455
原文鏈接:https://blog.csdn.net/xiaoanzi123/article/details/105094059/
