mybatis plus 配置多数据源(数据源进行切换)

多数据源( 数据源 进行切换)

AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。

1、application.yml中配置多个数据源

# Order
spring.datasource.order.url =jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.datasource.order.username =root
spring.datasource.order.password =123456
spring.datasource.order.driver-class-name =com.mysql.cj.jdbc.Driver
# Storage
spring.datasource.storage.url =jdbc:mysql://localhost:3306/seata_storage?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.datasource.storage.username =root
spring.datasource.storage.password =123456
spring.datasource.storage.driver-class-name =com.mysql.cj.jdbc.Driver
# Pay
spring.datasource.pay.url =jdbc:mysql://localhost:3306/seata_pay?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.datasource.pay.username =root
spring.datasource.pay.password =123456
spring.datasource.pay.driver-class-name =com.mysql.cj.jdbc.Driver

2、主启动类添加注解

@SpringBootApplication

@MapperScan("com.example.demo.mapper" )

3、编写配置类

@Getter
public enum DataSourceKey {
/**
* Order data source key.
*/
ORDER ,
/**
* Storage data source key.
*/
STORAGE ,
/**
* Pay data source key.
*/
PAY ,
}

public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = ThreadLocal.withInitial (DataSourceKey.ORDER ::name);
private static List<Object> dataSourceKeys = new ArrayList<>();
public static void setDataSourceKey(DataSourceKey key) {
CONTEXT_HOLDER .set(key.name());
}
public static String getDataSourceKey() {
return CONTEXT_HOLDER .get();
}
public static void clearDataSourceKey() {
CONTEXT_HOLDER .remove();
}
public static List<Object> getDataSourceKeys() {
return dataSourceKeys ;
}
}

public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
//log.info("当前数据源 [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey ();
}
}

@Configuration
public class DataSourceProxyConfig {
@Bean("originOrder" )
@ConfigurationProperties(prefix = "spring.datasource.order" )
public DataSource dataSourceMaster() {
return new DruidDataSource();
}
@Bean("originStorage" )
@ConfigurationProperties(prefix = "spring.datasource.storage" )
public DataSource dataSourceStorage() {
return new DruidDataSource();
}
@Bean("originPay" )
@ConfigurationProperties(prefix = "spring.datasource.pay" )
public DataSource dataSourcePay() {
return new DruidDataSource();
}

@Bean(name = "order" )
public DataSourceProxy masterDataSourceProxy(@Qualifier("originOrder" ) DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean(name = "storage" )
public DataSourceProxy storageDataSourceProxy(@Qualifier("originStorage" ) DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean(name = "pay" )
public DataSourceProxy payDataSourceProxy(@Qualifier("originPay" ) DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean("dynamicDataSource" )
public DataSource dynamicDataSource(@Qualifier("order" ) DataSource dataSourceOrder,
@Qualifier("storage" ) DataSource dataSourceStorage,
@Qualifier("pay" ) DataSource dataSourcePay) {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(3);
dataSourceMap.put(DataSourceKey.ORDER .name(), dataSourceOrder);
dataSourceMap.put(DataSourceKey.STORAGE .name(), dataSourceStorage);
dataSourceMap.put(DataSourceKey.PAY .name(), dataSourcePay);

dynamicRoutingDataSource.setDefaultTargetDataSource(dataSourceOrder);
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
DynamicDataSourceContextHolder.getDataSourceKeys ().addAll(dataSourceMap.keySet());
return dynamicRoutingDataSource;
}
@Bean
@ConfigurationProperties(prefix = "mybatis-plus" ) // MybatisSqlSessionFactoryBean中有各种MybatisPlus的配置属性(globalConfig、mapper L ocations}SqlSessionFactoryBean中则是mybatis的各种配置属性(typeAlies 、mapper L ocations )
public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource" ) DataSource dataSource) {
// 这里用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSource);
return mybatisSqlSessionFactoryBean;
}
}

调用切换数据源:

@GlobalTransactional
@Override
public OperationResponse placeOrder(PlaceOrderRequestVO placeOrderRequestVO) throws Exception {
DynamicDataSourceContextHolder. setDataSourceKey (DataSourceKey. ORDER ); //切换数据源
Integer amount = 1;
Integer price = placeOrderRequestVO.getPrice();
Order order = Order.builder ().build();
Integer saveOrderRecord = orderDao .insert(order);
// 扣减库存
boolean operationStorageResult = storageService .reduceStock(placeOrderRequestVO.getProductId(), amount);
// 扣减余额
boolean operationBalanceResult = payService .reduceBalance(placeOrderRequestVO.getUserId(), price);
DynamicDataSourceContextHolder. setDataSourceKey (DataSourceKey. ORDER ); //切换数据源
order.setStatus(OrderStatus.SUCCESS );
Integer updateOrderRecord = orderDao .updateById(order);
return success(operationStorageResult && operationBalanceResult);
}

项目启动报错: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured

原因:导入spring-mybatis依赖后,springboot启动时会自动加载数据源,由于dataSource配置成多数据源加载不到spring.datasource.url故而报错。

解决:1、主启动类添加@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

2、若上面配置还是无法解决,可以配置一个默认数据源让其启动时加载(不影响,会被多数据源切换时覆盖的):spring.datasource.url

额外:

SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);

SqlSession sqlSession=factory.openSession(); //sqlSession就是用来操作sql语句的

使用 MyBatis-Spring 之后, 会使用SqlSessionFactoryBean来代替SqlSessionFactoryBuilder创建SqlSessionFactory

MybatisPlus需要使用MybatisSqlSessionFactoryBean。

相关推荐
爱的叹息10 小时前
Spring和Spring Boot集成MyBatis的完整对比示例,包含从项目创建到测试的全流程代码
spring boot·spring·mybatis
与秋逐鹿¥18 小时前
在Mybatis中为什么要同时指定扫描mapper接口和 mapper.xml 文件,理论单独扫描 xml 文件就可以啊
java·tomcat·mybatis
爱的叹息18 小时前
MyBatis 插件开发的完整详细例子
mybatis
Minyy111 天前
SpringBoot程序的创建以及特点,配置文件,LogBack记录日志,配置过滤器、拦截器、全局异常
xml·java·spring boot·后端·spring·mybatis·logback
北辰浮光1 天前
[Mybatis-plus]
java·开发语言·mybatis
方圆想当图灵1 天前
由 Mybatis 源码畅谈软件设计(七):SQL “染色” 拦截器实战
后端·mybatis·代码规范
毅航1 天前
MyBatis 事务管理:一文掌握Mybatis事务管理核心逻辑
java·后端·mybatis
啊松同学2 天前
【Mybatis】MyBatisPlus的saveBatch真的是批量插入吗?深度解析与性能优化
java·后端·性能优化·mybatis
阿里小阿希2 天前
解决 Spring Boot + MyBatis 项目迁移到 PostgreSQL 后的数据类型不匹配问题
spring boot·postgresql·mybatis
凯酱2 天前
MyBatis-Plus分页插件的使用
java·tomcat·mybatis