SpringBoot+MyBatis+MySQL读写分离实现( 三 )
由于Spring容器中现在有4个数据源 , 所以我们需要为事务管理器和MyBatis手动指定一个明确的数据源 。
3.3. 设置路由key / 查找数据源
目标数据源就是那前3个这个我们是知道的 , 但是使用的时候是如果查找数据源的呢?
首先 , 我们定义一个枚举来代表这三个数据源
package com.cjs.example.enums;public enum DBTypeEnum {MASTER, SLAVE1, SLAVE2;}
接下来 , 通过ThreadLocal将数据源设置到每个线程上下文中
package com.cjs.example.bean;import com.cjs.example.enums.DBTypeEnum;import java.util.concurrent.atomic.AtomicInteger;public class DBContextHolder {private static final ThreadLocal
获取路由key
package com.cjs.example.bean;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import org.springframework.lang.Nullable;public class MyRoutingDataSource extends AbstractRoutingDataSource {@Nullable@Overrideprotected Object determineCurrentLookupKey() {return DBContextHolder.get();}}
设置路由key
默认情况下 , 所有的查询都走从库 , 插入/修改/删除走主库 。 我们通过方法名来区分操作类型(CRUD)
package com.cjs.example.aop;import com.cjs.example.bean.DBContextHolder;import org.apache.commons.lang3.StringUtils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Componentpublic class DataSourceAop {@Pointcut("!@annotation(com.cjs.example.annotation.Master) " +"}@Before("writePointcut()")public void write() {DBContextHolder.master();}/*** 另一种写法:if...else...判断哪些需要读从数据库 , 其余的走主数据库*///@Before("execution(* com.cjs.example.service.impl.*.*(..))")//public void before(JoinPoint jp) {//String methodName = jp.getSignature().getName();////if (StringUtils.startsWithAny(methodName, "get", "select", "find")) {//DBContextHolder.slave();//}else {//DBContextHolder.master();//}//}}
有一般情况就有特殊情况 , 特殊情况是某些情况下我们需要强制读主库 , 针对这种情况 , 我们定义一个主键 , 用该注解标注的就读主库
package com.cjs.example.annotation;public @interface Master {}
例如 , 假设我们有一张表member
package com.cjs.example.service.impl;import com.cjs.example.annotation.Master;import com.cjs.example.entity.Member;import com.cjs.example.entity.MemberExample;import com.cjs.example.mapper.MemberMapper;import com.cjs.example.service.MemberService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.List;@Servicepublic class MemberServiceImpl implements MemberService {@Autowiredprivate MemberMapper memberMapper;@Transactional@Overridepublic int insert(Member member) {return memberMapper.insert(member);}@Master@Overridepublic int save(Member member) {return memberMapper.insert(member);}@Overridepublic List
推荐阅读
- MagSafe皮革钱包上手:能塞3张卡片 放入口袋时会分离
- 水药分离设计+独立内胆,左点小仙智能足蒸器Z8表现无可挑剔
- 超高效 Vue 前后端分离cms管理系统LinCMS-Vue
- python文件读写模式,覆盖写和清空写你清楚了吗
- 群联第二代PCIe 4.0 SSD主控E18性能曝光:读写均超7GB/s
- 分离摇杆+16000DPI,旗舰电竞鼠标ROG魔刃标准版体验
- 国产良心SSD读写不虚标,379元入手512G,8秒开机
- vivo又开始秀了!这手机摄像头能分离
- Sharding-Jdbc之水平分库和读写分离(二)
- 2020年NAS首选,超高速读写备份,联想个人云存储A1体验