First of all, consider using cache for processing. If the cache is not enough, then use read-write separation for implementation
application.yml configures two data sources
#Default usage configuration spring: profiles: active: dev --- #Development and configuration 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 note that @ Mapper annotation is added to Mapper, and then it can be scanned to
@SpringBootApplication @EnableAutoConfiguration @MapperScan("com.xx.mobile.group.dao") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
DataSourceConfig.java note that there are three datasources
@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 pays attention to the injected DataSource and the order of the transaction annotation
@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("Switch to master"); } public static void slave() { set(DBTypeEnum.SLAVE); System.out.println("Switch to slave"); } }
Use slave annotation UseSlaveDatabase
public @interface UseSlaveDatabase { }
DataSourceAop pay attention to the Order of this aspect
@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() { } }
Test class
@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 { //The query method can use the above annotation } }
The related service dao mapper entity is not written Principle: multiple data sources are gathered on one data source (myRoutingDataSource), and then the facet is defined. If there is a UseSlaveDatabase annotation, the data source is set as the slave database, and the main database is used by default, because myRoutingDataSource.setDefaultTargetDataSource(masterDataSource); Note that the data source selection should be before the transaction, so the order of the aspect should be noted.