1.pom
mybatis-starter版本只能选2开头的版本,选3开头的就报错
<!--druid连接池-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.3</version>
</dependency><!--mybatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.1</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version><scope>runtime</scope>
</dependency><!-- 切面依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.yml配置
server:port: 9005servlet:context-path: /
# CREATE USER 'test1'@'localhost' IDENTIFIED BY 'test1'; 创建test1 用户#FLUSH PRIVILEGES; 刷新#grant all privileges on study.* to 'test1'@'localhost' with grant option; 把库study 授权给test1
spring:datasource:druid:master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/study?characterEncoding=utf-8username: test1password: test1#type: com.alibaba.druid.pool.DruidDataSourceslave:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/studyslave?characterEncoding=utf-8username: test1password: test1#type: com.alibaba.druid.pool.DruidDataSourceinitial-size: 5 #初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时max-active: 10 #最大连接池数量min-idle: 5 #最小连接池数量stat-view-servlet:enabled: true # 是否启用StatvViewServlet(监控页面),默认是falsetype: com.alibaba.druid.pool.DruidDataSourcemybatis:mapper-locations: mapper/*Mapper.xmlconfiguration:map-underscore-to-camel-case: true # 驼峰命名log-impl: org.apache.ibatis.logging.stdout.StdOutImpltype-aliases-package: study.entity
3. 初始化dataSource
package study.config;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** 项目初始化的时候将各个数据源注册到DynamicDataSource 中,其中firstDataSource作为默认数据源*/
@Configuration
public class DynamicDataSourceConfig {private static String MASTER = "master";private static String SLAVE = "slave";/*** 生成masterDataSource* @return*/@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(){return DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties("spring.datasource.druid.slave")public DataSource slaveDataSource(){return DruidDataSourceBuilder.create().build();}/*** 在一个有多个实例的Bean中使用@Primary注解来标记主要实例* @param masterDataSource* @param slaveDataSource* @return*/@Bean@Primarypublic DynamicRoutingDataSource dynamicDataSource(DataSource masterDataSource, DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(MASTER, masterDataSource);targetDataSources.put(SLAVE, slaveDataSource);return new DynamicRoutingDataSource(masterDataSource, targetDataSources);}}
4.继承AbstractRoutingDataSource
package study.config;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.Map;public class DynamicRoutingDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> DataSourceContextHolder = new ThreadLocal<>();/***** DynamicDataSourceConfig调用了这构造函数* @param defaultTargetDataSource* @param targetDataSources*/public DynamicRoutingDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {// 默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);// 所有的数据源super.setTargetDataSources(targetDataSources);// 初始化时,给resolvedDataSources 赋值super.afterPropertiesSet();}public static void setDataSource(String dataSource) {DataSourceContextHolder.set(dataSource);}public static String getDataSource() {return DataSourceContextHolder.get();}public static void clearDataSource() {DataSourceContextHolder.remove();}/*** 该类中还有一个determineTargetDataSource方法,* 是根据lookupkey从Map中获取对应的数据源,如果没有获取到,则使用默认的数据源* @return*/@Overrideprotected Object determineCurrentLookupKey() {return getDataSource();}
}
5.定义切换数据源的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {String value() default "";
}/**
* 定义切面,获取注解对应的dataSource
*/
package study.config.annotation;import com.alibaba.druid.util.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import study.config.DynamicRoutingDataSource;import java.lang.reflect.Method;@Aspect
@Component
public class DataSourceAspect {@Pointcut("@annotation(study.config.annotation.DS)")public void logPointCut() {}@Before("logPointCut()")public void doBefore(){System.out.println("方法执行前。");}@Around("logPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature)point.getSignature();Method method = signature.getMethod();DS ds = method.getAnnotation(DS.class);if(ds != null && !StringUtils.isEmpty(ds.value())){DynamicRoutingDataSource.setDataSource(ds.value());}try {return point.proceed();} finally {DynamicRoutingDataSource.clearDataSource();}}}
6.mapper定义
@Mapper
public interface UserMapper {@DS("master")@Select("select id as id, user_name as userName, password as password,create_time as createTime from t_user where id = #{id}")public UserInfo selectByIdFromMaster(@Param("id") Integer id);@Select("select id as id, user_name as userName, password as password,create_time as createTime from t_user where id = #{id}")public UserInfo selectByIdDefault(@Param("id") Integer id);@DS("slave")@Select("select id as id, user_name as userName, password as password,create_time as createTime from t_user where id = #{id}")public UserInfo selectByIdFromSlave(@Param("id") Integer id);}@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {private Integer id;private String userName;private String password;private Date createTime;private Date updateTime;public UserInfo(String userName, String password, Date createTime, Date updateTime) {this.userName = userName;this.password = password;this.createTime = createTime;this.updateTime = updateTime;}
}
6.service类
@Slf4j
@Service
public class UserServiceImpl {@Resourceprivate UserMapper userMapper;public List<UserInfo> selectById(int id){UserInfo userInfo1 = selectByIdDefault(2);UserInfo userInfo2 = selectByIdFromMaster(1);UserInfo userInfo3 = selectByIdFromSlave(5);log.info("userInfo1={}, userInfo2={}, userInfo3={}", userInfo1, userInfo2, userInfo3);return Arrays.asList(userInfo1, userInfo2);}/*** 从master库查询* @param id* @return*/public UserInfo selectByIdFromMaster(int id) {UserInfo userInfo = userMapper.selectByIdFromMaster(id);return userInfo;}/*** 从默认的库:master* @param id* @return*/public UserInfo selectByIdDefault(int id) {UserInfo userInfo = userMapper.selectByIdDefault(id);return userInfo;}/*** 从slave库查询* @param id* @return*/public UserInfo selectByIdFromSlave(int id) {return userMapper.selectByIdFromSlave(id);}}