2. 数据源配置8 8 1.8 org.springframework.boot spring-boot-starter-parent2.3.1.RELEASE org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-testtest com.baomidou mybatisplus-spring-boot-starter1.0.5 com.baomidou mybatis-plus2.1.8 org.springframework.boot spring-boot-starter-jdbcmysql mysql-connector-java5.1.34 runtime org.apache.velocity velocity-engine-core2.0 org.mybatis.spring.boot mybatis-spring-boot-starter1.3.1 com.baomidou dynamic-datasource-spring-boot-starter2.4.2 org.projectlombok lombokorg.springframework.boot spring-boot-maven-plugin
application.yml
server:
port: 8555
spring:
datasource:
dynamic:
#默认数据源
primary: master
datasource:
master:
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://43.138.47.28:3307/strength-test?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
slave_1:
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://43.138.47.28:3308/strength-test?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
logging:
config: classpath:logback-spring.xml
level:
root: debug
mybatis-plus:
mapper-locations: classpath:/mapper
public enum DBTypeEnum {
MASTER,
SLAVE1,
SLAVE2;
}
4.新建DataSourceContextHolder
接下来,通过ThreadLocal将数据源设置到每个线程上下文中
public class DataSourceContextHolder {
private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
private static final AtomicInteger COUNTER = new AtomicInteger(-1);
public static void set(DBTypeEnum dbType) {
CONTEXT_HOLDER.set(dbType);
}
public static DBTypeEnum get() {
return CONTEXT_HOLDER.get();
}
public static void clear(){
CONTEXT_HOLDER.remove();
}
public static void master() {
set(DBTypeEnum.MASTER);
System.out.println("切换到master");
}
public static void slave() {
// 轮询
int index = COUNTER.getAndIncrement() % 2;
if (COUNTER.get() > 9999) {
COUNTER.set(-1);
}
if (index == 0) {
set(DBTypeEnum.SLAVE1);
System.out.println("切换到slave1");
} else {
set(DBTypeEnum.SLAVE2);
System.out.println("切换到slave2");
}
}
}
5.设置路由key
public class MyRoutingDataSource extends AbstractRoutingDataSource {
@Nullable
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.get();
}
}
6.多数据源配置
@Configuration
public class DataSourceConfig {
@Bean(name = "master")
@ConfigurationProperties(prefix = "spring.datasource.druid.master" )
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "slave1")
@ConfigurationProperties(prefix = "spring.datasource.druid.slave1")
public DataSource slave1DataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "slave2")
@ConfigurationProperties(prefix = "spring.datasource.druid.slave2")
public DataSource slave2DataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
public DataSource myRoutingDataSource(@Qualifier("master") DataSource masterDataSource,
@Qualifier("slave1") DataSource slave1DataSource,
@Qualifier("slave2") DataSource slave2DataSource) {
Map
这里,我们配置了4个数据源,1个master,2两个slave,1个路由数据源。
7.MyBatis配置
@EnableTransactionManagement
@Configuration
public class MyBatisConfig {
@Resource(name = "myRoutingDataSource")
private DataSource myRoutingDataSource;
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(myRoutingDataSource);
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
return sqlSessionFactory.getObject();
}
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(myRoutingDataSource);
}
}
由于Spring容器目前有多个数据源,所以我们需要为事务管理器和MyBatis手动指定一个明确的数据源。
8.使用aop实现数据源切换默认情况下,插入/修改/删除走主库,取查询数据都是走从库。
package com.wenlinshan.masterslavedemo.aop;
import com.wenlinshan.masterslavedemo.config.DataSourceContextHolder;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DataSourceAop {
@Pointcut("!@annotation(com.wenlinshan.masterslavedemo.annotation.Master)" +
"&& (execution(* com.wenlinshan.masterslavedemo.service..*.select*(..)) " +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.get*(..)))")
public void readPointcut() {
}
@Pointcut("@annotation(com.wenlinshan.masterslavedemo.annotation.Master) " +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.insert*(..))" +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.save*(..))" +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.add*(..))" +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.update*(..))" +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.edit*(..))" +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.delete*(..))" +
"|| execution(* com.wenlinshan.masterslavedemo.service..*.remove*(..))")
public void writePointcut() {
}
@Before("readPointcut()")
public void read() {
DataSourceContextHolder.slave();
}
@Before("writePointcut()")
public void write() {
DataSourceContextHolder.master();
}
@After("readPointcut()")
public void readAfter() {
DataSourceContextHolder.clear();
}
@After("writePointcut()")
public void writeAfter() {
DataSourceContextHolder.clear();
}
}
9、测试
service
@Service public class TUserServiceImpl extends ServiceImpl10.controllerimplements TUserService { @Override @DS("") public Result add(UserDto user) { TUser tUser = new TUser(); tUser.setName(user.getName()); tUser.setCreateTime(new Date()); baseMapper.insert(tUser); return new Result(); } @DS("slave_1") @Override public Result getList() { return new Result(baseMapper.selectList(new EntityWrapper ().orderBy("id"))); } }
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private TUserService userService;
@PostMapping("add")
public Result test(@RequestBody UserDto user){
System.err.println("user===============>"+user);
return userService.add(user);
}
@PostMapping("list")
public Result getList(){
return userService.getList();
}
}
项目地址https://gitee.com/chenchensky/mybatis-plus-master.git


