In development, dynamic data source configuration is used a lot, such as in the use of multiple data sources, or switching between multiple DB. Here is a dynamic data source configuration scheme, both the two DB take mysql as an example.
Multiple data source configuration introduced
The introduction of mybatis and mysql in SpringBoot here is not said, do not understand can see springBoot mysql and mybatis introduction.
The data source configuration is as follows:
datasource:
master:
type: com.alibaba.druid.pool.DruidDataSource
jdbc-url: JDBC: mysql: / / 127.0.0.1:3306 / sbac_master? autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
log:
type: com.alibaba.druid.pool.DruidDataSource
jdbc-url: JDBC: mysql: / / 127.0.0.1:3306 / sbac_log? autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
Copy the code
The configuration of MyBatis is introduced as follows:
mybatis:
config-location: classpath:mybatis-config.xml
mapper-locations: classpath:com/lazycece/sbac/mysql/data/dao/*/mapper/*.xml
Copy the code
In this case, the springBoot automatic configuration function is used to configure myBatis information, but the data source is manually specified. Set master as the default data source with the master and log data sources specified:
@Configuration
public class MultiDataSource {
public static final String MASTER_DATA_SOURCE = "masterDataSource";
public static final String LOG_DATA_SOURCE = "logDataSource";
@Bean(name = MultiDataSource.MASTER_DATA_SOURCE)
@ConfigurationProperties(prefix = "datasource.master")
public DataSource masterDataSource(a) {
return DataSourceBuilder.create().build();
}
@Bean(name = MultiDataSource.LOG_DATA_SOURCE)
@ConfigurationProperties(prefix = "datasource.log")
public DataSource logDataSource(a) {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(a) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
Map<Object, Object> dataSourceMap = new HashMap<>(4);
dataSourceMap.put(MASTER_DATA_SOURCE, masterDataSource());
dataSourceMap.put(LOG_DATA_SOURCE, logDataSource());
dynamicDataSource.setTargetDataSources(dataSourceMap);
returndynamicDataSource; }}Copy the code
Dynamic data source routing implementation
With the configuration information in place, it’s time to talk about how to switch between multiple data sources. We are by implementing AbstractRoutingDataSource class determineCurrentLookupKey method to realize the dynamic routing of the data source, set the ThreadLocal variable stores the data source key thread protection, ensure between threads are not affected.
package com.lazycece.sbac.mysql.multi.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/ * * *@author lazycece
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSource.class);
private static final ThreadLocal<String> DATA_SOURCE_KEY = new ThreadLocal<>();
static void changeDataSource(String dataSourceKey) {
DATA_SOURCE_KEY.set(dataSourceKey);
}
static void clearDataSource(a) {
DATA_SOURCE_KEY.remove();
}
@Override
protected Object determineCurrentLookupKey(a) {
String key = DATA_SOURCE_KEY.get();
LOGGER.info("current data-source is {}", key);
returnkey; }}Copy the code
Then, it is to use THE METHOD of AOP to achieve dynamic switching of data sources, annotations and aspects are defined as follows:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DataSource {
String value(a);
}
@Component
@Aspect
public class DataSourceConfig {
@Before("@annotation(dataSource)")
public void beforeSwitchDataSource(DataSource dataSource) {
DynamicDataSource.changeDataSource(dataSource.value());
}
@After("@annotation(DataSource)")
public void afterSwitchDataSource(a) { DynamicDataSource.clearDataSource(); }}Copy the code
Dynamic data source switching use
Dynamic DataSource switching simply requires the business to use the @datasource annotation to indicate which DataSource to use, as shown below (only the key code is posted here) :
@Service
public class DynamicDataSourceServiceImpl implements DynamicDataSourceService {
@Resource
private UserDao userDao;
@Resource
private SystemLogDao systemLogDao;
@Override
@DataSource(value = MultiDataSource.MASTER_DATA_SOURCE)
public void addUserInfo(User user) {
userDao.insert(user);
}
@Override
@DataSource(value = MultiDataSource.MASTER_DATA_SOURCE)
public User getUserInfo(String username) {
return userDao.findByUsername(username);
}
@Override
@DataSource(value = MultiDataSource.LOG_DATA_SOURCE)
public void addSystemLog(SystemLog systemLog) {
systemLogDao.insert(systemLog);
}
@Override
@DataSource(value = MultiDataSource.LOG_DATA_SOURCE)
public List<SystemLog> getSystemLogInfo(Date beginTime, Date endTime) {
returnsystemLogDao.findByCreateTime(beginTime, endTime); }}Copy the code
Example source code
Case source address: github.com/lazycece/sp…