随着业务场景的复杂,单数据源已满足不了实际使用,多数源的配置成为了主流,笔者根据自己的项目经验总结了两种常用的多数据源配置方式,这里使用mybatis框架作为持久层,如何实现分享给大家||
第①种:定义多个数据源连接,mybatis配置好不同的数据源映射不同的dao及domain,通常同一个数据源会放到一个package下,即此包下的dao接口全是查同一个数据源的数据;
第②种:动态数据源切换,这种方式较为灵活,在程序运行时,把数据源动态织入到程序中,从而选择哪个源,主要用到的技术:annotation/spring aop/反射。
代码实现:以双数据源举例
①:
包目录:
1)主数据源配置类
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = {"com.bocom.datagenerate.dao.primaryDao"},sqlSessionFactoryRef ="primarySqlSessionFactory")
public class PrimaryConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix="spring.datasource")
public DataSource masterDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name = "primarySqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mybatis/primaryMybatis/*.xml"));
return sessionFactoryBean.getObject();
}
@Bean(name = "primaryTransactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("distrSqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory);
return template;
}
}
2)从数据源配置类
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.bocom.datagenerate.dao.taskPushDao",sqlSessionFactoryRef = "taskPushSqlSessionFactory")
public class TaskPushConfig {
@Bean(name = "taskPushDataSource")
@ConfigurationProperties(prefix="primary.datasource")
public DataSource masterDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name = "taskPushSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("taskPushDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mybatis/taskPushMybatis/*.xml"));
return sessionFactoryBean.getObject();
}
@Bean(name = "taskPushTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("taskPushDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("smpSqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("taskPushSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception{
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory);
return template;
}
}
ps:启动类上加上如下注解,以免报错
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
②:
参考了这篇文章https://www.cnblogs.com/surge/p/3582248.html,在此感谢博主分享!
首先,定义一个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
String value();
}
然后,定义一个aop类
@Aspect
@Component
public class DataSourceAspect {
@Before(value = "pointCut()")
public void before(JoinPoint point) {
Object target = point.getTarget();
String method = point.getSignature().getName();
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
try {
Method m = classz[0].getMethod(method, parameterTypes);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
DynamicDataSourceHoler.putDataSource(data.value());
System.out.println(data.value());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Pointcut("execution(* com.alibaba.ghs.task.mapper.*.*(..))")
public void pointCut() {
}
}
其次,写一个类DynamicDataSource 继承AbstractRoutingDataSource,实现其determineCurrentLookupKey() 方法,该方法返回Map的key,master或slave。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHoler.getDataSource();
}
}
class DynamicDataSourceHoler {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
public static void putDataSource(String name) {
holder.set(name);
}
public static String getDataSource() {
return holder.get();
}
}
最后,数据源配置类:
@Configuration
public class DataSourceConfig {
@Bean(name = "masterdatasource")
public DriverManagerDataSource driverManagerDataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://127.0.0.1:3306/ghs?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&allowMultiQueries=true");
ds.setUsername("root");
ds.setPassword("xxxx");
return ds;
}
@Bean(name = "slavedatasource")
public DriverManagerDataSource driverManagerDataSource2() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://127.0.0.1:3306/quartz?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&allowMultiQueries=true");
ds.setUsername("root");
ds.setPassword("xxxx");
return ds;
}
@Bean(name = "dataSource")
public DynamicDataSource dynamicDataSource(@Qualifier("masterdatasource") DriverManagerDataSource driverManagerDataSource,
@Qualifier("slavedatasource") DriverManagerDataSource driverManagerDataSource2) {
DynamicDataSource ds = new DynamicDataSource();
Map map = new HashMap();
map.put("master", driverManagerDataSource);
map.put("slave", driverManagerDataSource2);
ds.setTargetDataSources(map);
ds.setDefaultTargetDataSource(driverManagerDataSource);
ds.afterPropertiesSet();
return ds;
}
@Bean(name = "transcationManager")
public DataSourceTransactionManager manager(@Qualifier("dataSource") DynamicDataSource dynamicDataSource) {
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dynamicDataSource);
return manager;
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean sb(@Qualifier("dataSource") DynamicDataSource dynamicDataSource, ApplicationContext applicationContext) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mapper/*.xml"));
sqlSessionFactoryBean.setTypeAliasesPackage("com.alibaba.ghs.task.model");
return sqlSessionFactoryBean;
}
@Bean
public MapperScannerConfigurer MapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.alibaba.ghs.task.mapper"); //dao目录
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return mapperScannerConfigurer;
}
使用:
public interface GhsMapper {
@DataSource("master")
public void add(Ghs ghs);
@DataSource("slave")
public void add2(Ghs ghs);
}