赞
踩
实际开发中,进场可能遇到在一个引用中可能需要访问多个数据库的情况,以下是两种典型场景:
数据分布在不同的数据库汇总,数据库拆了,应用没拆。一个公司多个子项目,各用各的数据库,涉及数据共享。。。。

为了解决数据库的读性能瓶颈(读比写性能更高,写锁会影响读阻塞,从而影响读的性能)。
很多数据拥主从架构。也就是,一台主数据库服务器,对外提供增删改查的生产服务器;另一台从数据库服务器,主要进行读的操作。
可以通过中间件(ShardingSphere、mycat、mysql-proxy 、TDDL 。。。。) 但是有一些规模较小的公司,没有专门的中间件团队搭建读写分离基础设施,因此需要业务开发人员自行实现读写分离。

这里的框架与上图类似。 不同的是,在读写分离中,主库和从库的数据库是一致的(不考虑主从延迟)。数据更新操作(insert 、update、delete)都是在主库上进行的,主库将数据更新信息同步给
从库。在查询时,可以在从库上进行。从而分担主库的压力。
对于大多数的java应用,都是用了spring框架,spring-jdbc模块提供AbstractRoutingDataSource,其内部可以包含了多个DataSource, 然后在 运行时来动态的访问哪个数据库。这种方式访问数据的框架图如下所示:

应用直接操作的 AbstractRoutingDataSource的实现类,告诉AbstractRoutingDataSource访问哪个数据库,然后由AbstractRoutingDataSource从事先配置好的数据源(db1,db2) 选择一个,来访问对应的数据库。

应用直接操作的是abstractRoutingDataSource的实现类,告诉AbstractRoutingDataSource访问哪个数据库,然后由AbstractRoutingDataSource从事先配置好的数据源 (ds1,ds2)选择哪一个 ,来访问对应的数据库。

@Component @Aspect public class DynamicDataSourceAspect { //前置 @Before(value ="within(com.example.dynamic.datasource.service.impl.*) && @annotation(wr)") public void before( WR wr){ String value = wr.value(); RoutingDataSourceContext order = new RoutingDataSourceContext(value); System.out.println("数据源===="+value); } } @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface WR { String value() default "query"; } @RestController @RequestMapping("frend") @Slf4j public class FrendController { @WR @GetMapping("query") public List<menu> query(){ List<menu> list = menuService.list(); return list; } }
package com.example.dynamic.datasource.plugin; import com.alibaba.druid.sql.ast.statement.SQLCommentStatement; import com.example.dynamic.datasource.config.DynamicDataSource; import com.example.dynamic.datasource.config.RoutingDataSourceContext; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.util.Properties; /** * @ClassName:DynamicDataSourcePlugin * @Description: * @Author: * @Date:8/20/23 10:21 下午 * @Versiion:1.0 */ //1.如下配置 //2. 将文件加入到mybatis中去 //Intercepts 声明mybatis 固定的写法 //Signature 代表为mybatis 底层的哪个对象,去进行插件代理 @Intercepts({@Signature(type = Executor.class,method = "update",args = {MappedStatement.class,Object.class}), @Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class})}) public class DynamicDataSourcePlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //拿到当前方法【update、query】的所有参数 Object[] objects =invocation.getArgs(); //MappedStatement 封装sql MappedStatement ms = (MappedStatement) objects[0]; // if(ms.getSqlCommandType().equals(SqlCommandType.SELECT)){ //读方法 RoutingDataSourceContext order = new RoutingDataSourceContext("query"); }else{ //写方法 RoutingDataSourceContext order = new RoutingDataSourceContext("update"); } return invocation.proceed(); } @Override public Object plugin(Object target){ if(target instanceof Executor){ return Plugin.wrap(target,this); }else{ return target; } } @Override public void setProperties(Properties properties) { } }

在多数据源下,由于涉及到数据库的多个读写。一旦发生异常就可能会导致数据不一致的情况,在一种情况希望使用事务进行回退。但是spring的声明式食物再一次请求线程中只能使用一个数据源进行控制
但是对于多源数据库:
1.单一事务管理器(TransactionManager)无法切换数据源,需要配置多个TransactionManager。
2.@Transactionnal 是无法管理多个数据源的。如果像真正实现多源数据库事务控制,肯定是需要分布式事务。这里讲解多数据源事务控制 是一种变通的方式。
@Bean
pbulic DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager =new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
@Bean
public DataSourceTransactionManager transactionManager2(DynamiceDataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager =new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。