SpringBoot+mybatis+druid 多數據源實現

最近搞多數據源動態切換,根據不同的場景服務切換到不動的數據源上。從而實現分庫分表。

1、先看下我們項目的配置、pom.xml

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com</groupId>
	<artifactId>boot-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>boot-demo</name>
	<url>http://maven.apache.org</url>
	<!-- 引入springboot -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.0.RELEASE</version>
	</parent>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<!-- 添加web支持的starter pom -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.10</version>
			<!-- <exclusions>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>slf4j-api</artifactId>
				</exclusion>
			</exclusions> -->
		</dependency> 
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>tk.mybatis</groupId>
			<artifactId>mapper</artifactId>
			<version>4.0.4</version>
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>logback-classic</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>tk.mybatis</groupId>
			<artifactId>mapper-spring-boot-starter</artifactId>
			<version>1.2.4</version>
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>logback-classic</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<!-- <dependency>
			<groupId>org.apache.shardingsphere</groupId>
			<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
			<version>4.0.0-RC2</version>
		</dependency>
		<dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.0.0-RC2</version>
        </dependency> -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version><!--$NO-MVN-MAN-VER$ -->
			<scope>test</scope>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<!-- springboot的編譯插件 -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

application.properties

server.port=8012
server.servlet.context-path=/
server.tomcat.uri-encoding=UTF-8

# mybatis
mybatis.config-location=classpath:mybatis-config.xml
mybatis.mapper-locations=classpath:mapper/*.xml

# db 01
spring.datasource.data01.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.data01.url=jdbc:mysql://192.168.179.128:3306/TEST?characterEncoding=utf-8&useSSL=false
spring.datasource.data01.username=root
spring.datasource.data01.password=mynewPass4!
spring.datasource.data01.driverClassName=com.mysql.jdbc.Driver
spring.datasource.data01.initialSize=5
spring.datasource.data01.minIdle=5
spring.datasource.data01.maxActive=20
spring.datasource.data01.maxWait=60000
spring.datasource.data01.timeBetweenEvictionRunsMillis=60000
spring.datasource.data01.minEvictableIdleTimeMillis=300000
spring.datasource.data01.validationQuery=SELECT 1 FROM DUAL
spring.datasource.data01.testWhileIdle=true
spring.datasource.data01.testOnBorrow=false
spring.datasource.data01.testOnReturn=false
spring.datasource.data01.poolPreparedStatements=true
spring.datasource.data01.maxPoolPreparedStatementPerConnectionSize=20
#spring.datasource.data01.filters=stat,wall,log4j
spring.datasource.data01.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000



# db  02
spring.datasource.data02.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.data02.url=jdbc:mysql://192.168.179.128:3306/awa?characterEncoding=utf-8&useSSL=false
spring.datasource.data02.username=root
spring.datasource.data02.password=mynewPass4!
spring.datasource.data02.driverClassName=com.mysql.jdbc.Driver
spring.datasource.data02.initialSize=5
spring.datasource.data02.minIdle=5
spring.datasource.data02.maxActive=20
spring.datasource.data02.maxWait=60000
spring.datasource.data02.timeBetweenEvictionRunsMillis=60000
spring.datasource.data02.minEvictableIdleTimeMillis=300000
spring.datasource.data02.validationQuery=SELECT 1 FROM DUAL
spring.datasource.data02.testWhileIdle=true
spring.datasource.data02.testOnBorrow=false
spring.datasource.data02.testOnReturn=false
spring.datasource.data02.poolPreparedStatements=true
spring.datasource.data02.maxPoolPreparedStatementPerConnectionSize=20
#spring.datasource.data02.filters=stat,wall,log4j
spring.datasource.data02.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000




 

現在我們來說下實現過程;

1、編寫java代碼配置類

package com.boot.config;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;

/**
 * 多數據源切換,只差AOP了
 * 
 * @author zpl
 *
 */
 @Configuration
public class DataSourceConfig {

	@Bean(name = "dataSource01")
	@ConfigurationProperties(prefix = "spring.datasource.data01") // application.properteis中對應屬性的前綴
	public DataSource dataSource01() {
		return DruidDataSourceBuilder.create().build();
	}

	@Bean(name = "dataSource02")
	@ConfigurationProperties(prefix = "spring.datasource.data02") // application.properteis中對應屬性的前綴
	public DataSource dataSource02() {
		return DruidDataSourceBuilder.create().build();
	}

	@Bean(name = "dataSource")
	@Primary // 多數據源的情況下,這個註解很關鍵,否則報:expected single matching bean but found 3:
				// dataSource01,dataSource02,dataSou
	public DataSource dataSource() {
		DataSourceRouting routing = new DataSourceRouting();
		DataSource dataSource01 = dataSource01();
		// 設置默認數據源
		routing.setDefaultTargetDataSource(dataSource01);

		// 配置多數據源
		Map<Object, Object> dataSources = new ConcurrentHashMap<Object, Object>();
		dataSources.put(DataSourceRouting.DATA_SOURCE_MASTER, dataSource01);
		dataSources.put(DataSourceRouting.DATA_SOURCE_SUB, dataSource02());
		routing.setTargetDataSources(dataSources);
		return routing;
	}

	// @Bean
	// public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws
	// Exception
	// {
	// SqlSessionFactoryBean sqlSessionFactoryBean = new
	// SqlSessionFactoryBean();
	// //設置數據源
	// sqlSessionFactoryBean.setDataSource(dataSource);
	// //指定基礎包
	// sqlSessionFactoryBean.setTypeAliasesPackage("com.microservice.dbandcache.model");
	// //指定mapper位置
	// sqlSessionFactoryBean.setMapperLocations(new
	// PathMatchingResourcePatternResolver()
	// .getResources("classpath:mapping/*.xml"));
	//
	// return sqlSessionFactoryBean.getObject();
	// }

}

這裏設置了多數據源,並且在啓動類上的註解去掉自動配置數據源的配置類
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
2、配置多數據源路由,需要切換數據源的時候,將threadlocal 中的副本改成需要的數據源

package com.boot.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 動態數據源路由
 * 
 *
 * @date 2018年9月21日 上午11:06:01
 *
 */
public class DataSourceRouting extends AbstractRoutingDataSource {

	public static final String DATA_SOURCE_MASTER = "dataSourceMaster";
	public static final String DATA_SOURCE_SUB = "dataSourceSub";
	private static final ThreadLocal<String> localContext = new ThreadLocal<String>();
	private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceRouting.class);

	@Override
	protected Object determineCurrentLookupKey() {
		if (null == localContext.get()) {
			return null;
		}
		LOGGER.info("數據源切換至" + localContext.get());
		return localContext.get();
	}

	public static void setMasterDataSource() {
		localContext.set(DATA_SOURCE_MASTER);
	}

	public static void setSubDataSource() {
		localContext.set(DATA_SOURCE_SUB);
	}

}

3、當我們的Idao 接口類調用數據庫操作時,會通過determineCurrentLookupKey獲取數據源名,具體的實現原理可以看源碼AbstractRoutingDataSource 的實現。
4、這樣我們就可以在執行對應的方法之前先將ThreadLocal 的內容改變成需要的數據源key.從而改變數據源。

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-===============================================

再想一想,按照上面的實現感覺有點low,在每次執行方法之前就得硬編碼切換一下。而我們使用的是mybatis ,我們的Idao接口都有@Mapper ,所以我們用的接口方法都是統一的。那怎麼才能更便捷點呢
方法1、自定義註解,在IDao 接口上添加,並給值爲指定的數據源類型。在執行方法的時候我們可以攔截到接口上的註解,從而獲取到註解的數據源類型配置,從而通過路由DataSourceRouting 來這是ThreadLocal中的數據源key.

package com.boot.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.boot.enums.DataSourceConst;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
	DataSourceConst.DataSourceType value() default DataSourceConst.DataSourceType.dataSourceMaster;
}
package com.boot.enums;

public interface DataSourceConst {
	enum DataSourceType {
		dataSourceMaster, dataSourceSub
	}

}
package com.boot.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(-1)
public class DynamicDataSourceAspect {

	@Before("execution(* com.*.mapper..*.*(..))")
	public void before(JoinPoint point) {
		// 本來想通過攔截接口上的註解,通過註解的值來獲取需要的數據源,然後通過dataSourceRouting來設置,但是研究過後,發現無法攔截接口上的註解

	}

	@After("execution(* com.*.mapper..*.*(..))")
	public void after(JoinPoint point) {
		DataSourceRouting.clearDataSource();
	}
}

DynamicDataSourceAspect  是攔截器,但是通過一天的查詢測試,始終無法通過joinpoint來獲取到接口上的註解,但是我們通過point.getTarget();可以看到代理mapperproxy 中的interfacemapper 中確實有該註解,卻始終沒有攔截到。很無語,最終查到aopUtils,網上說通過aopUtils ,springboot 2.x能拿到,但是我是始終沒拿到。如果知道的請指教。。。

這種方法不行,我們只能在mybatis 中操作了

通過查詢,我們可以配置@mapperscan 來給他掃描的包下的Idao類指定對應的sqlsessionFactory.

配置如下

package com.boot.mapper.first;

import org.apache.ibatis.annotations.Mapper;

import com.boot.annotation.TargetDataSource;
import com.boot.bean.User;
import com.boot.enums.DataSourceConst.DataSourceType;
@Mapper
//@TargetDataSource(DataSourceType.dataSourceMaster)
public interface IUserDao extends tk.mybatis.mapper.common.Mapper<User> {

}
package com.boot.mapper.second;

import org.apache.ibatis.annotations.Mapper;

import com.boot.annotation.TargetDataSource;
import com.boot.bean.User;
import com.boot.enums.DataSourceConst.DataSourceType;
@Mapper
//@TargetDataSource(DataSourceType.dataSourceSub)
public interface IUserDao2 extends tk.mybatis.mapper.common.Mapper<User> {

}

以上兩類是Idao 接口的實現。繼承 tk.mybatis.mapper.common.Mapper。可以實現父類接口方法來自定義方法修改實現,這個不是重點。
再來看配置類

package com.boot.config;

import javax.sql.DataSource;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
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.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;

import tk.mybatis.spring.annotation.MapperScan;

/**
 * 分庫-01庫配置
 * 
 * @author zpl
 *
 */
@Configuration
@MapperScan(basePackages = "com.boot.mapper.first", sqlSessionFactoryRef = "SqlSessionFactoryfirst")
public class DataSourceFirstConfig {

	@Bean(name = "dataSource01")
	@ConfigurationProperties(prefix = "spring.datasource.data01") // application.properteis中對應屬性的前綴
	public DataSource dataSource01() {
		return DruidDataSourceBuilder.create().build();
	}

	@Bean(name="SqlSessionFactoryfirst")
	public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource01") DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		// 設置數據源
		sqlSessionFactoryBean.setDataSource(dataSource);
		// 指定基礎包
		sqlSessionFactoryBean.setTypeAliasesPackage("com.boot.bean.*");
		// 指定mapper位置
		sqlSessionFactoryBean
				.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
		return sqlSessionFactoryBean.getObject();
	}

}
package com.boot.config;

import javax.sql.DataSource;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
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 com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;

import tk.mybatis.spring.annotation.MapperScan;

/**
 * 分庫-01庫配置
 * 
 * @author zpl
 *
 */
@Configuration
@MapperScan(basePackages = "com.boot.mapper.second", sqlSessionFactoryRef = "SqlSessionFactorysecond")
public class DataSourceSecondConfig {

	@Bean(name = "dataSource02")
	@ConfigurationProperties(prefix = "spring.datasource.data02") // application.properteis中對應屬性的前綴
	public DataSource dataSource02() {
		return DruidDataSourceBuilder.create().build();
	}

	@Bean(name = "SqlSessionFactorysecond")
	public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource02") DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		// 設置數據源
		sqlSessionFactoryBean.setDataSource(dataSource);
		// 指定基礎包
		sqlSessionFactoryBean.setTypeAliasesPackage("com.boot.bean.*");
		// 指定mapper位置
		sqlSessionFactoryBean
				.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));

		return sqlSessionFactoryBean.getObject();
	}

}

上面的是配置類。配置了兩個數據源,並給指定的包下面Idao接口配置了指定的數據源的sqlsessionFactory.
其中遇到的問題,
1、指定mapper位置,原先寫的是classpath:mapper/*.xml;
但是啓動報錯。錯誤如下:

Caused by: java.io.FileNotFoundException: class path resource [mapper/] cannot be resolved to URL because it does not exist
	at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:195) ~[spring-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at org.springframework.core.io.support.PathMatchingResourcePatternResolver.findPathMatchingResources(PathMatchingResourcePatternResolver.java:497) ~[spring-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(PathMatchingResourcePatternResolver.java:298) ~[spring-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at com.boot.config.DataSourceSecondConfig.sqlSessionFactory(DataSourceSecondConfig.java:43) ~[classes/:na]
	at com.boot.config.DataSourceSecondConfig$$EnhancerBySpringCGLIB$$c22d62aa.CGLIB$sqlSessionFactory$0(<generated>) ~[classes/:na]
	at com.boot.config.DataSourceSecondConfig$$EnhancerBySpringCGLIB$$c22d62aa$$FastClassBySpringCGLIB$$793b95be.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at com.boot.config.DataSourceSecondConfig$$EnhancerBySpringCGLIB$$c22d62aa.sqlSessionFactory(<generated>) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	... 46 common frames omitted

找不到mapper的路徑,不知道爲啥,改成classpath*:mapper/*.xml 就好了。

問題2:原先@MapperScan(basePackages = "com.boot.mapper.second", sqlSessionFactoryRef = "SqlSessionFactorysecond") 中指定basePackages的值是,com.boot.mapper.second.* ,本意想讓他掃com.boot.mapper.second 包中的接口類,但是啓動報錯,錯誤如下:

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'com.boot.mapper.second.IUserDao2' that could not be found.


Action:

Consider defining a bean of type 'com.boot.mapper.second.IUserDao2' in your configuration.

意思是創建IUserDao2 的實例bean 失敗,通過嘗試,分析原因是,basePackages 指定的是包名,會掃指定包下的類,如果後面多了個.* ,那麼它就會掃second 包下的其他包下的接口。而自己包下的接口類就掃不到了,故創建不了bean。而我們的controller類引用了該接口實例類。所以報錯。

以上問題都解決調之後,我們就嘗試執行了下,如代碼:

package com.boot.controller;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.boot.bean.User;
import com.boot.config.DataSourceRouting;
import com.boot.mapper.first.IUserDao;
import com.boot.mapper.second.IUserDao2;

@RestController
@RequestMapping("/data")
public class DataSourceController {

//	@Resource
//	private SqlSessionFactory sqlSessionFactory;
	@Resource
	private IUserDao userDao;
	@Resource
	private IUserDao2 userDao2;

//	@RequestMapping("/swith.json")
//	public void dataSwitch() {
//		DataSourceRouting.setMasterDataSource();
//		try {
//			Connection conenction = sqlSessionFactory.openSession().getConnection();
//			DataSourceRouting.setSubDataSource();
//			Connection conenction2 = sqlSessionFactory.openSession().getConnection();
//			System.out.println(conenction.getMetaData().getUserName());
//			System.out.println(conenction.getCatalog()); // 數據庫名稱
//			System.out.println(conenction2.getMetaData().getUserName());
//			System.out.println(conenction2.getCatalog()); // 數據庫名稱
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
//	}

	@RequestMapping("/insert.json")
	public void insert() {
		List<User> list = new ArrayList<User>();
		list.add(new User(null, 1, "張三1", 1));
		list.add(new User(null, 2, "張三2", 2));
		list.add(new User(null, 3, "張三3", 3));
		list.add(new User(null, 4, "張三4", 4));
		list.add(new User(null, 5, "張三5", 5));
		list.add(new User(null, 6, "張三6", 6));
		for (User u : list) {
			Integer userId = u.getUserId();
			if (userId % 2 == 0) {
				userDao.insert(u);
			} else {
				userDao2.insert(u);
			}

		}
	}

}

   啓動的時候還報錯:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method sqlSessionTemplate in tk.mybatis.mapper.autoconfigure.MapperAutoConfiguration required a single bean, but 2 were found:
	- SqlSessionFactoryfirst: defined by method 'sqlSessionFactory' in class path resource [com/boot/config/DataSourceFirstConfig.class]
	- SqlSessionFactorysecond: defined by method 'sqlSessionFactory' in class path resource [com/boot/config/DataSourceSecondConfig.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

根據提示,我們發現,在啓動springBoot的時候mapper有個自動配置,MapperAutoConfiguration,會配置sqlsessionFactory,而且只配置其中一個,導致啓動失敗,因爲我們有兩個,它不知道用哪個了。所以報錯。

所以我們在啓動springBoot的時候,加上
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,MapperAutoConfiguration.class})
不走它的自動配置,用我們自己的配置,

注意:::
我們如果多數據源按照上面配置的話,我們的@MapperScan 註解就不能再startApplication 啓動類上面加了。
 

有時間的話我們研究下使用tk.mybatis 實現分表。如何實現分表。以及它是如何實現查詢的,,橫向分表難度比較大的就是查詢,連表查詢,以及排序,聚合等操作查詢,。主流的有mycat, sharding-sphere(原噹噹[sharding-jdbc]升級版本)。
thanks everyone!!!

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章