下面是详细讲解“SpringBoot多数据源配置的全过程记录”的完整攻略。
概述
在实际开发中,我们很可能需要同时连接多个数据库,例如连接MySQL和Redis等。SpringBoot的多数据源配置能够满足我们这一需求。本文将详细记录SpringBoot多数据源配置的全过程。
步骤
1. 添加依赖
在pom.xml
文件中添加以下依赖:
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- MySQL连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!-- Redis客户端 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.5.4</version>
</dependency>
2. 配置application.yml文件
在src/main/resources
目录下创建application.yml
文件,并添加以下配置:
spring:
datasource:
master: # 主数据源配置
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_master?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: password
slave: # 从数据源配置
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_slave?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: password
redis:
host: localhost
port: 6379
password: password
database: 0
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
3. 配置数据源
在com.example.demo.config
包下创建DataSourceConfig
类,并添加以下代码:
@Configuration
public class DataSourceConfig {
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource(){
return DataSourceBuilder.create().build();
}
}
4. 配置MyBatis Plus
在com.example.demo.config
包下创建MybatisPlusConfig
类,并添加以下代码:
@Configuration
@MapperScan(basePackages = "com.example.demo.mapper")
public class MybatisPlusConfig {
@Resource(name = "masterDataSource")
private DataSource masterDataSource;
@Resource(name = "slaveDataSource")
private DataSource slaveDataSource;
/**
* 主数据源 MyBatis SqlSessionFactory
*/
@Bean(name = "masterSqlSessionFactory")
public SqlSessionFactory masterSqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(masterDataSource);
return sessionFactory.getObject();
}
/**
* 从数据源 MyBatis SqlSessionFactory
*/
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory slaveSqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(slaveDataSource);
return sessionFactory.getObject();
}
/**
* 主数据源 MyBatis 事务管理
*/
@Bean(name = "masterTransactionManager")
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource);
}
/**
* 从数据源 MyBatis 事务管理
*/
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager slaveTransactionManager() {
return new DataSourceTransactionManager(slaveDataSource);
}
/**
* 主数据源 MyBatis Mapper 接口类扫描包配置
*/
@Bean(name = "masterSqlSessionTemplate")
public SqlSessionTemplate masterSqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(masterSqlSessionFactory());
}
/**
* 从数据源 MyBatis Mapper 接口类扫描包配置
*/
@Bean(name = "slaveSqlSessionTemplate")
public SqlSessionTemplate slaveSqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(slaveSqlSessionFactory());
}
}
5. 配置事务
在com.example.demo.config
包下创建TransactionConfig
类,并添加以下代码:
@Configuration
public class TransactionConfig {
@Resource(name = "masterDataSource")
private DataSource masterDataSource;
@Resource(name = "slaveDataSource")
private DataSource slaveDataSource;
@Bean(name = "dynamicTransactionManager")
public PlatformTransactionManager dynamicTransactionManager() {
// 通过DynamicDataSource类中的两个数据源创建动态数据源
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
Map<Object, Object> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("master", masterDataSource);
dataSourceMap.put("slave", slaveDataSource);
dynamicDataSource.setTargetDataSources(dataSourceMap);
//设置当前线程使用的数据源,默认使用主数据源
dynamicDataSource.afterPropertiesSet();
return new DataSourceTransactionManager(dynamicDataSource);
}
}
6. 配置动态数据源
在com.example.demo.config
包下创建DynamicDataSource
类,并添加以下代码:
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.get();
}
}
7. 配置数据源上下文
在com.example.demo.config
包下创建DataSourceContextHolder
类,并添加以下代码:
public class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void set(String dataSourceType) {
CONTEXT_HOLDER.set(dataSourceType);
}
public static String get() {
return CONTEXT_HOLDER.get();
}
public static void clear() {
CONTEXT_HOLDER.remove();
}
public static boolean isMaster() {
return "master".equals(get());
}
public static boolean isSlave() {
return "slave".equals(get());
}
}
8. 配置AOP切面
在com.example.demo.aspect
包下创建DataSourceAspect
类,并添加以下代码:
@Component
@Aspect
public class DataSourceAspect {
@Pointcut("@annotation(com.example.demo.annotation.Slave)")
public void dataSourceSlave() {
}
@Before("dataSourceSlave()")
public void before(JoinPoint joinPoint){
System.out.println("切换到从数据源");
DataSourceContextHolder.set("slave");
}
@After("dataSourceSlave()")
public void after(JoinPoint joinPoint){
System.out.println("从数据源操作完成,切换回主数据源");
DataSourceContextHolder.clear();
}
}
9. 配置Mapper
在com.example.demo.mapper
包下创建UserMapper
类,并添加以下代码:
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Slave
List<User> selectAllFromSlave();
}
10. 测试代码
现在我们已经配置好了多数据源,下面就来测试一下吧。
@SpringBootTest
class DemoApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void testMaster() {
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
@Test
void testSlave() {
List<User> users = userMapper.selectAllFromSlave();
System.out.println(users);
}
}
运行以上测试代码,可以看到控制台输出如下:
[User(id=1, name=Tom, age=18), User(id=2, name=Jerry, age=21)]
切换到从数据源
[User(id=3, name=Kate, age=30), User(id=4, name=Lucy, age=25)]
从数据源操作完成,切换回主数据源
11. 示例说明
以上只是一个简单的示例,更多的多数据源配置方式也会有所不同。另外,上面的示例中,我们只是手动在代码中切换了从数据源,实际上我们可以通过配置MyBatis Plus来实现自动切换数据源。
例如,我们可以通过实现com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
接口来实现自动切换数据源,例如:
public class DynamicDataSourceInterceptor implements MybatisPlusInterceptor {
private static final ThreadLocal<String> holder = new ThreadLocal<String>();
public static void putDataSource(String name) {
holder.set(name);
}
public static void clearDataSource() {
holder.remove();
}
@Override
public void intercept(SqlSession sqlSession, Invocation invocation) throws Throwable {
String dataSourceName = holder.get();
if (dataSourceName == null) {
invocation.proceed();
return;
}
DynamicDataSource dynamicDataSource = (DynamicDataSource) applicationContext.getBean("dynamicDataSource");
dynamicDataSource.setDataSource(dataSourceName);
try {
invocation.proceed();
} finally {
dynamicDataSource.clearDataSource();
}
}
}
以上就是SpringBoot多数据源配置的全过程记录。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot多数据源配置的全过程记录 - Python技术站