springboot mybatis讀寫分離的一個實現方案
阿新 • • 發佈:2019-05-18
首先考慮使用快取來處理,如果快取不夠用,再使用讀寫分離來實現
application.yml配置兩個資料來源
#預設使用配置 spring: profiles: active: dev --- #開發配置 spring: profiles: dev datasource: master: jdbc-url: jdbc:mysql://localhost:3812/test username: user password: pwd driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource slave: jdbc-url: jdbc:mysql://localhost:3812/test username: user password: pwd driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource
Application.java 注意Mapper上加@Mapper註解,然後可以被掃描到
@SpringBootApplication
@EnableAutoConfiguration
@MapperScan("com.xx.mobile.group.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
DataSourceConfig.java 注意有三個DataSource
@Configuration public class DataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.slave") public DataSource slave1DataSource() { return DataSourceBuilder.create().build(); } @Bean public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slave1DataSource") DataSource slave1DataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DBTypeEnum.MASTER, masterDataSource); targetDataSources.put(DBTypeEnum.SLAVE, slave1DataSource); DataSourceRouting myRoutingDataSource = new DataSourceRouting(); myRoutingDataSource.setDefaultTargetDataSource(masterDataSource); myRoutingDataSource.setTargetDataSources(targetDataSources); return myRoutingDataSource; } }
DBType
public enum DBTypeEnum {
MASTER, SLAVE;
}
MybatisConfig 注意注入的DataSource,注意事務註解的order
@EnableTransactionManagement(order = 2)
@Configuration
public class MyBatisConfig {
@Resource(name = "myRoutingDataSource")
private DataSource myRoutingDataSource;
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(myRoutingDataSource);
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(myRoutingDataSource);
}
}
DataSourceRouting
public class DataSourceRouting extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.get();
}
}
DBContextHolder
public class DBContextHolder {
private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();
private static final AtomicInteger counter = new AtomicInteger(-1);
public static void set(DBTypeEnum dbType) {
contextHolder.set(dbType);
}
public static DBTypeEnum get() {
return contextHolder.get();
}
public static void master() {
set(DBTypeEnum.MASTER);
System.out.println("切換到master");
}
public static void slave() {
set(DBTypeEnum.SLAVE);
System.out.println("切換到slave");
}
}
使用從庫註解UseSlaveDatabase
public @interface UseSlaveDatabase {
}
DataSourceAop 注意此切面的Order
@Aspect
@Component
public class DataSourceAop implements Ordered{
@Override
public int getOrder() {
return 0;
}
@Before("readPointcut()")
public void read() {
DBContextHolder.slave();
}
@Pointcut("@annotation(com.xx.mobile.config.UseSlaveDatabase)")
public void readPointcut() {
}
}
測試類
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TestTask {
@Autowired
private ITaskService taskService;
@Test
public void save() throws Exception {
}
@Test
public void query() throws Exception {
//query方法可以用上面的註解
}
}
相關的service dao mapper entity沒有寫
原理:多個數據源彙集到一個數據源上(myRoutingDataSource),然後定義切面,遇到有UseSlaveDatabase註解就設定資料來源為從庫,預設使用主庫,因為myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
注意資料來源選擇要在是事務之前,所以切