java实现读写分离
前言:项目启动过程中有错,未解决,这里仅是实现思路
一,业务场景:新增,修改,删除操作主库,查询操作从库
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实现读写分离相关推荐
- Java之读写分离实现
Java之读写分离实现 需求说明 解决方案 Sharding-JDBC 实现步骤 MySQL主从复制环境搭建 数据库创建 Maven项目搭建 数据源配置 测试样例 总结 存在问题 参考地址 需求说明 ...
- java读取mysql配置文件_一文读懂 MySQL 主从复制读写分离
文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary 前言 在很多项目,特别是互联网项目,在使用MySQL时都会采用主从复 ...
- java spring mysql配置_java相关:mysql+spring+mybatis实现数据库读写分离的代码配置
java相关:mysql+spring+mybatis实现数据库读写分离的代码配置 发布于 2020-4-4| 复制链接 分享一篇关于关于mysql+spring+mybatis实现数据库读写分离的代 ...
- java读取mysql配置文件_Linux运维:MySQL读写分离解决方案
一次性付费进群,长期免费索取教程,没有付费教程. 进微信群回复公众号:微信群:QQ群:460500587 教程列表 见微信公众号底部菜单 | 本文底部有推荐书籍 微信公众号:计算机与网络安全 I ...
- mysql读写分离java配置方法_springboot配置数据库读写分离
为什么要做数据库读写分离 大多数互联网业务,往往读多写少,这时候,数据库的读会首先称为数据库的瓶颈,这时,如果我们希望能够线性的提升数据库的读性能,消除读写锁冲突从而提升数据库的写性能,那么就可以使用 ...
- mybatis 配置多数据源 java,SpringBoot+MyBatisPlus配置多数据源读写分离
首先呢,我们这里使用MySQL的数据库,可以简单配置一下主从备份来实现两个数据库的数据同步 项目的配置目录大概是这样的作为参考 第一步.定义一个枚举类声明当前的数据源类型 package com.yu ...
- sqlserver AlwaysOn实现读写分离配置及java/net代码实现
1.用读写分离的原因: O.读写量很大,为了提升数据库读写性能,将读写进行分离: O.如果多机房下写少读多,同时基于数据一致性考虑,只有一个主库存入所有的数据写入,本地再做从库提供读取,减少多机房间直 ...
- java mongo replica_mongo 的replica set的集群模式 实现读写分离
对于replica set 中的secondary 节点默认是不可读的.在写多读少的应用中,使用Replica Sets来实现读写分离.通过在连接时指定或者在主库指定slaveOk,由Secondar ...
- Java 实现数据库读写分离竟如此简单?
目录 1.介绍 2.ShardingJDBC 3.入门案例 4.测试 4.1 增加 4.2 删除 4.3 修改 4.4 查询 1.介绍 面对日益增加的系统访问量,数据库的吞吐量面临着巨大的瓶颈,可能有 ...
- Java实现数据库读写分离
java读写分离的实现 1. 背景 我们一般应用对数据库而言都是"读多写少",也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案, 其中一个是主库,负责写入 ...
最新文章
- Windows 7 应用程序崩溃恢复
- 03、Swagger2和Springmvc整合详细记录(爬坑记录)
- springmvc返回数据中文乱码
- outlook html阅读,Html Email 邮件html页编写指南
- ABP虚拟文件系统(VirtualFileSystem)实例------定制菜单栏显示用户姓名
- centos8启动docker-mysql8容器
- enmo_day_06
- 学习sql注入:猜测数据库_学习SQL:SQL数据类型
- 咚咚咚————【封装驱动】3.97寸800*480高清IPS驱动封装otm8009显示IC
- 计算机usb接口电压不稳定,如何处理笔记本电脑USB接口的电源不足或电压不稳定?...
- 小小知识点(十九)护眼色豆沙绿的设置
- element-ui 删除input框尾部默认图标和获取焦点边框高亮问题
- 台湾Google云计算计划负责人叶平讲解云计算
- 女程序员在互联网界到底有没有被歧视?
- python什么字体好看_七个不一样的Python代码写法,让你写出一手漂亮的代码
- 【NOIP 2015】斗地主
- 数据库系统实验4:SQL——SELECT查询操作
- RecyclerView滚动指定条目并在页面中居中
- 微信小程序云数据库中实现分页
- 数据分析知识体系与校招时间线
热门文章
- ORM数据库框架 LitePal SQLite MD
- 以index访问Tensor元素+ 反池化 unpool TensorFlow代码
- Android Cursor浅析
- windows执行命令来运行loadrunner录制好的脚本(收藏)
- CentOS下Privoxy和Iptables 实现透明代理,修改http-header
- iOS开发 frame 与 bounds 的区别与关系
- windows下编译Chrome浏览器
- 嵌入式工具——iperf
- 加一条平行于y轴的直线_Hepco海普克应用案例—直线V型滚轮导轨广泛应用于多轴机械手...
- 为什么手工drop_caches之后cache值并未减少?