目录
多数据源实现
yml配置文件
配置类
业务代码
案例演示
多数据源实现
yml配置文件
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedatasource1:url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=falseusername: rootpassword: 123456initial-size: 1min-idle: 1max-active: 20test-on-borrow: truedriver-class-name: com.mysql.cj.jdbc.Driverdatasource2:url: jdbc:mysql://127.0.0.1:3306/datasource2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=falseusername: rootpassword: 123456initial-size: 1min-idle: 1max-active: 20test-on-borrow: truedriver-class-name: com.mysql.cj.jdbc.Driver
创建两个数据库分别为datasource1、datasource2,在两个数据中分别创建一张friend表
配置类
配置两个DataSource的Bean
@Configuration
public class DataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.datasource1")public DataSource dataSource1() {// 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.datasource2")public DataSource dataSource2() {// 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}@Beanpublic DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}@Beanpublic DataSourceTransactionManager transactionManager2(DynamicDataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}
}
@Component
@Primary // 将该Bean设置为主要注入Bean
public class DynamicDataSource extends AbstractRoutingDataSource {// 当前使用的数据源标识public static ThreadLocal<String> name=new ThreadLocal<>();// 写@AutowiredDataSource dataSource1;// 读@AutowiredDataSource dataSource2;// 返回当前数据源标识@Overrideprotected Object determineCurrentLookupKey() {return name.get();}@Overridepublic void afterPropertiesSet() {// 为targetDataSources初始化所有数据源Map<Object, Object> targetDataSources=new HashMap<>();targetDataSources.put("W",dataSource1);targetDataSources.put("R",dataSource2);super.setTargetDataSources(targetDataSources);// 为defaultTargetDataSource 设置默认的数据源super.setDefaultTargetDataSource(dataSource1);super.afterPropertiesSet();}
}
继承AbstractRoutingDataSource类,定义一个threadlocal线程变量,并将两个数据源自动注入,在重写的afterPropertiesSet方法中(该方法是bean初始化后执行的方法),将两个数据源放入到spring管理的数据源中,通过重写的determineCurrentLookupKey方法返回W或R表示读库或写库。
业务代码
@RestController
@RequestMapping("friend")
@Slf4j
public class FrendController {@Autowiredprivate FrendService frendService;@GetMapping(value = "select")public List<Friend> select(){return frendService.list();}@GetMapping(value = "insert")public String insert(){Friend friend = new Friend();friend.setName("张三");frendService.save(friend);return "success";}
}
public interface FrendService {List<Friend> list();void save(Friend frend);}
@Service
public class FrendImplService implements FrendService {@AutowiredFrendMapper frendMapper;@Override
// @WR("R") // 库2public List<Friend> list() {DynamicDataSource.name.set("R");return frendMapper.list();}@Override
// @WR("W") // 库1public void save(Friend frend) {DynamicDataSource.name.set("W");frendMapper.save(frend);}}
在具体的实现当中,先通过DynamicDataSource设置需要的操作的数据库。或者可以用注解的方式来实现,注解配置如下:
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface WR {String value() default "W";
}
@Component
@Aspect
public class DynamicDataSourceAspect implements Ordered {// 前置@Before("within(com.dynamic.datasource.service.impl.*) && @annotation(wr)")public void before(JoinPoint point, WR wr){String name = wr.value();DynamicDataSource.name.set(name);System.out.println(name);}}
通过切面的方式,获取到当前方法需要操作的数据库。
案例演示
启动项目后,执行select请求
执行insert请求
查看数据库
发现datasource1有数据,datasource2无数据。
如果上述两种数据库是主从的话,此种方式可以实现主从数据库,主库写入,从库负责读。