环境概览
- Spring Boot 2.1.0.RELEASE
- AspectJ Weaver 1.9.2
- Mysql 5.6.28
前言介绍
在日常的项目开发中,存在某些sql查询效率低,或因为并发瓶颈受限于数据库。所以我们需要实现读写分析,对于慢sql,或者大并发的sql查询语句,实现读写分离,负载均衡。在技术上,目前有很多JAVA中间件可以实现读写分离,例如当当的Sharding-JDBC,美团的DBProxy等。本文将介绍如何在Spring Boot中不依赖第三方框架配置读写分离。
项目结构
项目地址
具体实现
- 实现AbstractRoutingDataSource抽象方法,动态切换数据源
@Bean
public AbstractRoutingDataSource routingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>(2);
targetDataSources.put(DataSourceContextHolder.MASTER, masterDataSource);
targetDataSources.put(DataSourceContextHolder.SLAVE, slaveDateSource);
// 路由类,寻找对应的数据源
AbstractRoutingDataSource proxy = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
String key = DataSourceContextHolder.getMaterOrSlave();
if (key == null) {
return DataSourceContextHolder.MASTER;
}
return key;
}
};
// 默认库
proxy.setDefaultTargetDataSource(masterDataSource);
proxy.setTargetDataSources(targetDataSources);
return proxy;
}
- 创建切面选择数据源
@EnableAspectJAutoProxy
@Aspect
@Component
public class DataSourceChangeAop {
private final String slaveAop = "@annotation(com.noral.multidatasource.configuration.annotation.SlaveDataSource)";
private final String masterAop = "@annotation(com.noral.multidatasource.configuration.annotation.MasterDataSource)";
@Before(slaveAop)
public void changeToSlaveDataSource() {
DataSourceContextHolder.setSlave();
}
@Before(masterAop)
public void changeToMasterDataSource() {
DataSourceContextHolder.setMaster();
}
@After("(" + slaveAop + "||" + masterAop + ")")
public void after() {
DataSourceContextHolder.clear();
}
}
- 创建方法测试
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Person getPerson() {
Person person = jdbcTemplate.queryForObject("select * from person", new BeanPropertyRowMapper<>(Person.class));
return person;
}
@Override
@SlaveDataSource
public Person getPersonSlave() {
Person person = jdbcTemplate.queryForObject("select * from person", new BeanPropertyRowMapper<>(Person.class));
return person;
}
@Override
@MasterDataSource
public Person getPersonMaster() {
Person person = jdbcTemplate.queryForObject("select * from person", new BeanPropertyRowMapper<>(Person.class));
return person;
}
}
结果
@Test
public void testForChangeDataSource() {
System.out.println(personService.getPerson());
//Person{id=1, name='datasource1'}
System.out.println(personService.getPersonSlave());
//Person{id=2, name='datasource2'}
System.out.println(personService.getPersonMaster());
//Person{id=1, name='datasource1'}
}