前言:项目启动过程中有错,未解决,这里仅是实现思路

一,业务场景:新增,修改,删除操作主库,查询操作从库

1,主,从库配置,通过配置类,分别读取主从库配置信息,创建不同数据源,并设置不同数据源

2,通过aop区分,不同标识的方法,使用ThreadLocal记录当前线程的数据源key

二,代码

1,AOP

@Component
@Aspect
public class DataSourceAop {//主库切点,标注了DataSourceMaster注解或者方法名为insert,update等开头的方法,走主库@Pointcut("@annotation(com.anji.allways.business.payment.ReadWriteDataSourceAop.DataSourceMasterAnno)" +"|| execution(* com.anji.allways.business.payment.controller..*.insert*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.add*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.update*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.edit*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.delete*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.remove*(..))")public void masterPointcut() {}//从库切点,没有标注了DataSourceMaster注解且方法名为select,get等开头的方法,走从库@Pointcut("!@annotation(com.anji.allways.business.payment.ReadWriteDataSourceAop.DataSourceMasterAnno)" +"&& (execution(* com.anji.allways.business.payment.controller..*.select*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.get*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.find*(..))" +"|| execution(* com.anji.allways.business.payment.controller..*.query*(..)))")public void slavePointcut() {}@Before("masterPointcut()")public void master() {DynamicDataSourceHolderAop.markMaster();}@Before("slavePointcut()")public void slave() {DynamicDataSourceHolderAop.markSlave();}
}
2,数据源配置
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = DataSourceConfig.PACKAGE)
public class DataSourceConfig {//public class DataSourceConfig extends MybatisAutoConfiguration {static final String PACKAGE = "com.anji.allways.business.sales.mapper";/*    public DataSourceConfig(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {super(properties, interceptorsProvider, resourceLoader, databaseIdProvider, configurationCustomizersProvider);}*//*** 主库数据源* @return*/@Bean@ConfigurationProperties(prefix = "primary.datasource")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}/*** 从库数据源* @return*/@Bean@ConfigurationProperties(prefix = "secondary.datasource")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}/*    @Bean@Overridepublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {return super.sqlSessionFactory(dataSource());}*//*** 自定义数据源,内部持有了主库和从库数据源* 通过某种机制应用程序读取不同数据源* @param masterDataSource* @param slaveDataSource* @return*/@Beanpublic DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) {MyRoutingDataSource proxy = new MyRoutingDataSource();Map<Object, Object> targetDataResources = new HashMap<>();targetDataResources.put(DataSourceType.MASTER, masterDataSource);targetDataResources.put(DataSourceType.SLAVE, slaveDataSource);//当方法没有别aop拦截,默认主库proxy.setDefaultTargetDataSource(masterDataSource());proxy.setTargetDataSources(targetDataResources);proxy.afterPropertiesSet();return proxy;}
}

3,

数据源的key
/*** 使用ThreadLocal技术来记录当前线程中的数据源的key** @author zhijun*/
public class DynamicDataSourceHolderAop {//使用ThreadLocal记录当前线程的数据源keyprivate static final ThreadLocal<String> holder = new ThreadLocal<String>();/*** 设置数据源key** @param key*/public static void putDataSourceKey(String key) {holder.set(key);}/*** 获取数据源key** @return*/public static String getDataSourceKey() {return holder.get();}/*** 标记写库*/public static void markMaster() {putDataSourceKey(DataSourceType.MASTER.toString());}/*** 标记读库*/public static void markSlave() {putDataSourceKey(DataSourceType.SLAVE.toString());}}

4,数据源路由

public class MyRoutingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceHolderAop.getDataSourceKey();}
}

5,自定义主数据源注解

/*** <pre>* 主数据源自定义注解* </pre>** @author shenke* @version $Id: LoggerManage.java, v 0.1 2018年3月16日 上午9:40:56 wanglong Exp $*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceMasterAnno {String description();
}

6,数据源类型枚举

/*** 主库从库标记key*/
public enum DataSourceType {MASTER, SLAVE;
}

7,测试

测试1

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class DatasourceApplicationTest {private static Logger logger = LoggerFactory.getLogger(DatasourceApplicationTest.class);@Autowiredprivate TradeMapper tradeMapper;/*** 从从库中读取-开发库*/@Testpublic void readData() {TradeVo tradeVo = new TradeVo();List<TradeVo> listSecond = tradeMapper.selectTrade(tradeVo);log.info("从库secondary dataSource size:{}", listSecond.size());}/*** 从主库中读取-测试库*/@Testpublic void insertTest() {TradeVo tradeVo = new TradeVo();List<TradeVo> listP = tradeMapper.selectTrade(tradeVo);logger.info("主库primary dataSource size:{}", listP.size());}}

测试二

@Slf4j
@RestController
@RequestMapping("/dataSource")
public class ReadWriteController {private static Logger logger = LoggerFactory.getLogger(ReadWriteController.class);@Autowiredprivate TradeMapper tradeMapper;/*** 从从库中读取-开发库*/@RequestMapping("readMaster")public void readData() {TradeVo tradeVo = new TradeVo();List<TradeVo> listSecond = tradeMapper.selectTrade(tradeVo);log.info("从库secondary dataSource size:{}", listSecond.size());}/*** 从主库中读取-测试库*/@RequestMapping("readSlave")public void insertTest() {TradeVo tradeVo = new TradeVo();List<TradeVo> listP = tradeMapper.selectTrade(tradeVo);logger.info("主库primary dataSource size:{}", listP.size());}}

java实现读写分离相关推荐

  1. Java之读写分离实现

    Java之读写分离实现 需求说明 解决方案 Sharding-JDBC 实现步骤 MySQL主从复制环境搭建 数据库创建 Maven项目搭建 数据源配置 测试样例 总结 存在问题 参考地址 需求说明 ...

  2. java读取mysql配置文件_一文读懂 MySQL 主从复制读写分离

    文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary 前言 在很多项目,特别是互联网项目,在使用MySQL时都会采用主从复 ...

  3. java spring mysql配置_java相关:mysql+spring+mybatis实现数据库读写分离的代码配置

    java相关:mysql+spring+mybatis实现数据库读写分离的代码配置 发布于 2020-4-4| 复制链接 分享一篇关于关于mysql+spring+mybatis实现数据库读写分离的代 ...

  4. java读取mysql配置文件_Linux运维:MySQL读写分离解决方案

    一次性付费进群,长期免费索取教程,没有付费教程. 进微信群回复公众号:微信群:QQ群:460500587  教程列表 见微信公众号底部菜单 |  本文底部有推荐书籍  微信公众号:计算机与网络安全 I ...

  5. mysql读写分离java配置方法_springboot配置数据库读写分离

    为什么要做数据库读写分离 大多数互联网业务,往往读多写少,这时候,数据库的读会首先称为数据库的瓶颈,这时,如果我们希望能够线性的提升数据库的读性能,消除读写锁冲突从而提升数据库的写性能,那么就可以使用 ...

  6. mybatis 配置多数据源 java,SpringBoot+MyBatisPlus配置多数据源读写分离

    首先呢,我们这里使用MySQL的数据库,可以简单配置一下主从备份来实现两个数据库的数据同步 项目的配置目录大概是这样的作为参考 第一步.定义一个枚举类声明当前的数据源类型 package com.yu ...

  7. sqlserver AlwaysOn实现读写分离配置及java/net代码实现

    1.用读写分离的原因: O.读写量很大,为了提升数据库读写性能,将读写进行分离: O.如果多机房下写少读多,同时基于数据一致性考虑,只有一个主库存入所有的数据写入,本地再做从库提供读取,减少多机房间直 ...

  8. java mongo replica_mongo 的replica set的集群模式 实现读写分离

    对于replica set 中的secondary 节点默认是不可读的.在写多读少的应用中,使用Replica Sets来实现读写分离.通过在连接时指定或者在主库指定slaveOk,由Secondar ...

  9. Java 实现数据库读写分离竟如此简单?

    目录 1.介绍 2.ShardingJDBC 3.入门案例 4.测试 4.1 增加 4.2 删除 4.3 修改 4.4 查询 1.介绍 面对日益增加的系统访问量,数据库的吞吐量面临着巨大的瓶颈,可能有 ...

  10. Java实现数据库读写分离

    java读写分离的实现 1.  背景 我们一般应用对数据库而言都是"读多写少",也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案, 其中一个是主库,负责写入 ...

最新文章

  1. Windows 7 应用程序崩溃恢复
  2. 03、Swagger2和Springmvc整合详细记录(爬坑记录)
  3. springmvc返回数据中文乱码
  4. outlook html阅读,Html Email 邮件html页编写指南
  5. ABP虚拟文件系统(VirtualFileSystem)实例------定制菜单栏显示用户姓名
  6. centos8启动docker-mysql8容器
  7. enmo_day_06
  8. 学习sql注入:猜测数据库_学习SQL:SQL数据类型
  9. 咚咚咚————【封装驱动】3.97寸800*480高清IPS驱动封装otm8009显示IC
  10. 计算机usb接口电压不稳定,如何处理笔记本电脑USB接口的电源不足或电压不稳定?...
  11. 小小知识点(十九)护眼色豆沙绿的设置
  12. element-ui 删除input框尾部默认图标和获取焦点边框高亮问题
  13. 台湾Google云计算计划负责人叶平讲解云计算
  14. 女程序员在互联网界到底有没有被歧视?
  15. python什么字体好看_七个不一样的Python代码写法,让你写出一手漂亮的代码
  16. 【NOIP 2015】斗地主
  17. 数据库系统实验4:SQL——SELECT查询操作
  18. RecyclerView滚动指定条目并在页面中居中
  19. 微信小程序云数据库中实现分页
  20. 数据分析知识体系与校招时间线

热门文章

  1. ORM数据库框架 LitePal SQLite MD
  2. 以index访问Tensor元素+ 反池化 unpool TensorFlow代码
  3. Android Cursor浅析
  4. windows执行命令来运行loadrunner录制好的脚本(收藏)
  5. CentOS下Privoxy和Iptables 实现透明代理,修改http-header
  6. iOS开发 frame 与 bounds 的区别与关系
  7. windows下编译Chrome浏览器
  8. 嵌入式工具——iperf
  9. 加一条平行于y轴的直线_Hepco海普克应用案例—直线V型滚轮导轨广泛应用于多轴机械手...
  10. 为什么手工drop_caches之后cache值并未减少?