动态数据源
需求:就是不同模块要存在不同的数据库中,就要实现动态数据源
基本思路:
1.创建一个动态的数据源DynamicDataSource,同事创建一个配置类DynamicDataSourceConfig配置类,这个配置类在Spring初始化的时候就在动态数据源中配置两种数据源
2.创建自定义注解@DataSource 标注在dao接口方法上,表明用哪个数据源
3.aop切入我们dao方法是,接口自定义注解给DynamicDataSource设置用哪个数据源
这样不同的dao层的方法通过@DataSource就可以自定义我们需要用的数据源
代码
自定义注解:
/**
* 备注:自定义数据源选择注解
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}
配置类:
@Configuration
@Component
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid.xiaobin-master")
public DataSource xiaobinMasterDataSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.druid.xiaobin-slave")
public DataSource xiaobinSlaveDataSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource(DataSource xiaobinMasterDataSource, DataSource xiaobinSlaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("xiaobin-master",xiaobinMasterDataSource);
targetDataSources.put("xiaobin-slave", xiaobinSlaveDataSource);
return new DynamicDataSource(xiaobinMasterDataSource, targetDataSources);
}
}
切面:
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.dynamicdatasource.demo.Config.DataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource dataSource = method.getAnnotation(DataSource.class);
if(dataSource == null){
DynamicDataSource.setDataSource("xiaobin-master");
}else {
DynamicDataSource.setDataSource(dataSource.name());
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
}
dao层接口:
@Mapper
public interface UserMapper {
@DataSource(name = "xiaobin-master")
public Map queryAllWithMaster();
@DataSource(name = "xiaobin-master")
Map queryAllWithSlave();
}
配置文件中配置两个数据源:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
xiaobin-master: # 主数据源
driverClassName: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/mydb1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8
xiaobin-slave: # 从数据源
driverClassName: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/mydb2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8
mybatis:
mapper-locations: classpath:mapper/*.xml
controller:
@RestController
@RequestMapping
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/{name}/list")
public Map list(@PathVariable("name")String name){
if(name.equals("master")){
return userMapper.queryAllWithMaster();
}else{
return userMapper.queryAllWithSlave();
}
}
}
另外主启动类中要导入我们自定义的配置类
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) // 把默认的配置类排除掉
@MapperScan(basePackages = "com.dynamicdatasource.demo.Dao")
@Import({DynamicDataSourceConfig.class}) //导入
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
mapper文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dynamicdatasource.demo.Dao.UserMapper">
<select id="queryAllWithMaster" resultType="java.util.Map">
select * from mydb1.user t where t.NAME = 'zs'
</select>
<select id="queryAllWithSlave" resultType="java.util.Map">
select * from mydb2.course t where t.c = '1'
</select>
</mapper>
- 更新:对于数据源用TheadLocal 保证每个线程的数据源不一样的,spring中对象是单例的,不用TheadLocal会把其他的线程的数据源修改了。