Spring Boot combines Mybatis to solve the problem of multiple data sources

     Recently, I am researching Spring Cloud to build microservices. For a huge system, it needs to be divided into multiple microservices. Each service is equivalent to a module, responsible for different things, and each performs its own duties. Of course, the databases also need to be Keep it relatively independent, so multiple databases need to be involved, so how to use Spring Boot to configure multiple data sources?

     First, we need a custom annotation named: DataSource

@Retention(RetentionPolicy.RUNTIME)//The annotation is defined at the runtime level 
@Target(ElementType.METHOD)//The annotation is applied to the method
public @interface DataSource {

String value() default "user";
}
Then create The class of the data source: DynamicDataSourceHolder
public class DynamicDataSourceHolder {

/**
* 默认数据源
*
*/
public static final String DEFAULT_DATASOURCE = "user";

public static final ThreadLocal<String> holder = new ThreadLocal<String>();

public static void setDataSource(String name) {
holder.set(name);
}

public static String getDataSouce() {
return holder.get();
}

public static void clearDataSouce() {
holder.remove();
}

}

配置动态数据源的类: DynamicDataSource

   

public class DynamicDataSource extends AbstractRoutingDataSource { 

@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSouce();
}

}

Then we generate the data source and create the MybatisConfig class

  

@Configuration 
@PropertySource("classpath:jdbc.properties") //Introduce the information in the configuration file jdbc.properties
@MapperScan(basePackages ={"com.drive.dbuser.dao"} , sqlSessionFactoryRef = "sqlSessionFactory")   // 配置Mapper作用的位置
public class MybatisConfig {

@Bean(name = "user")
@ConfigurationProperties(prefix = "user")
public DataSource dataSourceUser(){
return DataSourceBuilder.create().build();
} //生成user数据源

@Bean(name = "drive")
@ConfigurationProperties(prefix = "drive")
public DataSource dataSourceDrive(){
return DataSourceBuilder.create().build();
} //生成drive数据源


@Bean(name = "order")
@ConfigurationProperties(prefix = "order")
public DataSource dataSourceOrder(){
return DataSourceBuilder.create().build();
} //生成order数据源

@Bean(name = "dynamicDataSource")
public DataSource dataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源---User
dynamicDataSource.setDefaultTargetDataSource(dataSourceUser());
// 配置多数据源
Map<Object, Object> dataSourceMap = new HashMap(5);
dataSourceMap.put("user", dataSourceUser());
dataSourceMap.put("drive", dataSourceDrive());
dataSourceMap.put("order", dataSourceOrder());
dynamicDataSource.setTargetDataSources(dataSourceMap);
return dynamicDataSource;
} //配置多数据源

@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource()); //
//添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
factoryBean.setMapperLocations(resolver.getResources("classpath*:com/drive/dbuser/mapper/*.xml")); //生效的位置
return factoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}//Create Session Factory
/* @Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception { //SqlSessionTemplate is the core of MyBatis-Spring. This class is responsible for managing MyBatis's SqlSession, calling MyBatis's SQL method
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory()); // Use the Factory
return template configured above;
}*/
}

Let's take a look at the information of the configuration file of jdbc.properties :
#User service library 
user.url=jdbc:mysql:***
user.username=***
user.password= *** #Taxi
service library
drive.url=
drive.username= drive.password=
#Order
service library
order .url=
order.username=
order.password=1

user.driverClassName=com.mysql.jdbc.Driver
drive.driverClassName=com.mysql.jdbc.Driver
order.driverClassName=com.mysql.jdbc.Driver



In this way, our multiple data sources are configured, so how to call it, for example, I need to go to the user database to check the data, and then go to the drive database to add data, so how to dynamically change the data source?
We can use a large core AOP in Spring, first we need to enable AOP in the application.properties file
spring.aop.auto=true #Turn 
on AOP

and then create the DataSourceAspect class,
@Aspect 
@Component
public class DataSourceAspect {

@Pointcut("execution(* com.drive.dbuser.dao.*.*(..))")
public void declareJointPointExpression() {
}

@Before("declareJointPointExpression()")
public void beforeSwitchDS(JoinPoint point){
//Get the currently accessed class
Class<?>[] className = point.getTarget().getClass().getInterfaces();
//Get the accessed method name
String methodName = point.getSignature( ).getName();
//Get the parameter type of the method
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DynamicDataSourceHolder.DEFAULT_DATASOURCE;
try {
// Get the method object accessed
Method method = className[0].getMethod(methodName, argClass);
// Determine if there is @DataSource annotation
if (method.isAnnotationPresent(DataSource.class)) {
DataSource annotation = method.getAnnotation(DataSource.class);
// Take out The data source name in the
annotation dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// Switch the data source
DynamicDataSourceHolder.setDataSource(dataSource);
}


@After("declareJointPointExpression()" )
public void afterSwitchDS(JoinPoint point){
DynamicDataSourceHolder.clearDataSouce();
}

}

At this time, let's take a look at the content of the Dao layer:
@DataSource("user")
List<CustomerVO> selectCustomer(CustomerVO customerVO);

We create an aspect class. Before we call the Dao layer, we will first check the annotation on the method on the Mapper interface, and inject it into the DynamicDataSourceHolder as a data source, so that we can dynamically switch the data source.

Finally, we need to add the startup class
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) //Avoid loading unnecessary automation configuration by disabling the specified automation configuration 
@EnableConfigurationProperties //The annotation is used to enable support for the @ConfigurationProperties annotation configuration bean, which tells Spring Boot Enable support for @ConfigurationProperties: annotations are mainly used to convert properties configuration files into beans for use

Of course, don't forget to configure the required dependencies in pom.xml:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>



<!-- Spring Boot Mybatis 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>

<!-- MySQL 连接驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>

<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId> Well, you're done, friends who like it remember to follow me!</dependency>
<version>1.2.16</version>








Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325818529&siteId=291194637