代码中建议在service(业务)层进行主从分离。同一个service方法内部不建议再进行主从分离。这里是事务切面层,我们知道,在同一个事务中会使用同一条链接进行处理,在业务层方法内部逻辑不再建议进行主从分离,避免数据不一致问题的出现。
以下方案通过 继承 AbstractRoutingDataSource类+注解+aop+ThreadLocal 实现注解方式的数据源的动态切换
1、读数据库切换注解类,在service注解表示开启读库操作,自动方法完成后自动清空数据源数据
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Inherited
public @interface SlaveDataSource {
}
2、spring aop切面类
@Aspect
public class DataSourceAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceAspect.class);
public static final String MASTER = "master";
public static final String SLAVE = "slave";
@Before(value = "execution(* *(..)) && @annotation(SlaveDataSource)")
public void before(JoinPoint point) {
String clazz = point.getTarget().getClass().getName();
String name = point.getSignature().getName();
LOGGER.debug(clazz+"."+name+" --- datasource---> :"+SLAVE);
DataSourceHolder.putDataSource(SLAVE);
}
@After(value = "execution(* *(..)) && @annotation(SlaveDataSource)")
public void after(JoinPoint joinPoint) {
DataSourceHolder.clearDataSourceType();
}
注意,需要开启springAop配置,同时将对象反向注入
3、动态数据源类,继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSource();
}
}
4、数据源处理类
public class DataSourceHolder {
public static final ThreadLocalHOLDER = new ThreadLocal();
public static void putDataSource(String datasource) {
HOLDER.set(datasource);
}
public static String getDataSource() {
return HOLDER.get();
}
public static void clearDataSourceType() {
HOLDER.remove();
}
}
springMybatis.xml的配置,注:使用的为阿里的druid数据库连接池,如果使用dbcp请自行切换
使用方式:对service方法上添加注解切换数据源,默认为主库
@Service
public class PingServiceImpl implements PingService {
private final BasicConfigDao basicConfigDao;
@Autowired
public PingServiceImpl(BasicConfigDao basicConfigDao) {
this.basicConfigDao = basicConfigDao;
}
@Override
public void pingMaster() {
basicConfigDao.ping();
}
@SlaveDataSource
@Override
public void pingSalve() {
basicConfigDao.ping();
}
}