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。

相关推荐
李昊哲小课2 天前
Spring Boot 4 旅游主题实战教程 阶段三:数据持久化
spring boot·后端·mybatis·旅游
datalover2 天前
MYBATIS=PLUS批量插入数据提效
mybatis
南城以南溫暖如初1472 天前
从零搭建24小时自助健身系统:技术选型与核心模块实战
java·spring boot·redis·mysql·vue·mybatis
小江的记录本3 天前
【ORM 框架】MyBatis-Plus 核心特性、条件构造器、分页插件、乐观锁插件(附《思维导图》、《问题排查与实践清单》和《面试高频考点汇总》)
java·windows·spring boot·python·spring·面试·mybatis
小江的记录本3 天前
【ORM框架】MyBatis核心原理、ORM思想、MyBatis vs JPA
java·数据库·后端·spring·spring cloud·oracle·mybatis
qq_485015213 天前
MyBatis-Plus 3.x FieldStrategy 作用
java·数据库·mybatis
布谷歌4 天前
如何自定义 MyBatis枚举处理器(EnumTypeHandler):分享从 “同包同名 shadow 覆盖” 到 “官方扩展点” 的重构经历
重构·mybatis
南城以南溫暖如初1474 天前
树洞交友系统架构设计与匿名聊天实战指南
java·spring boot·mysql·系统架构·vue·mybatis·交友
凯酱5 天前
MyBatis 中 OGNL 的使用:从入门到实战
java·tomcat·mybatis
蓝缘6 天前
解决main No MyBatis mapper was found in 的警告
mybatis