springBoot 动态数据源以及Mybatis多数据源
来源:互联网 发布:windows小键盘 编辑:程序博客网 时间:2024/06/06 18:36
前言
在开发过程中可能需要用到多个数据源,比如一个项目(MySQL)就是和(SQL Server)混合使用,就需要使用多数据源;如果业务场景比较复炸,可以使用动态数据源,灵活切换,典型的应用就是读写分离。下面分两个模块来配置数据源,大家可以根据自己实际情况配置。
多数据源
禁用DataSourceAutoConfiguration
如果DataSourceAutoConfiguration不禁用的话,就会报错,多个数据源,无法装配哪一个。在springBoot的主程序入口的注解
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class})
配置application.properties
#datasource 这是自动装配的默认配置禁止,这里不能使用#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource#spring.datasource.driver-class-name=com.mysql.jdbc.Driver#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/api_resources?#autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true#spring.datasource.username=api#spring.datasource.password=api#db1spring.datasource.db1.url=jdbc:mysql://127.0.0.1:3306/api_resources?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=truespring.datasource.db1.username=apispring.datasource.db1.password=apispring.datasource.db1.driver-class-name=com.mysql.jdbc.Driver#db2spring.datasource.db2.url=jdbc:mysql://127.0.0.1:3306/ssm?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=truespring.datasource.db2.username=apispring.datasource.db2.password=apispring.datasource.db2.driver-class-name=com.mysql.jdbc.Driver
配置dataSource
配置两个数据源,分别为db1,和db2
/** * Author: Starry.Teng * Email: tengxing7452@163.com * Date: 17-11-1 * Time: 下午9:14 * Describe: DataSource Config */@Configurationpublic class DataSourceConfig { @Autowired Environment env; @Bean(name = "ds1") public DataSource dataSource1() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(env.getProperty("spring.datasource.db1.url")); dataSource.setUsername(env.getProperty("spring.datasource.db1.username")); dataSource.setPassword(env.getProperty("spring.datasource.db1.password")); dataSource.setDriverClassName(env.getProperty("spring.datasource.db1.driver-class-name")); return dataSource; } @Bean(name = "ds2") public DataSource dataSource2() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(env.getProperty("spring.datasource.db2.url")); dataSource.setUsername(env.getProperty("spring.datasource.db2.username")); dataSource.setPassword(env.getProperty("spring.datasource.db2.password")); dataSource.setDriverClassName(env.getProperty("spring.datasource.db2.driver-class-name")); return dataSource; }}
Mybatis配置
为两个数据源分贝配置一个MybatisDb1Config类和MybatisDb2Config类,对数据源进行管理,注意他们所管理的包是不同的。
/** * Author: Starry.Teng * Email: tengxing7452@163.com * Date: 17-11-1 * Time: 下午9:15 * Describe: MybatisDb1 Config */@Configuration@MapperScan(basePackages = {"cn.yjxxclub.demo.datasource.dao.db1"}, sqlSessionFactoryRef = "sqlSessionFactory1")public class MybatisDb1Config { @Qualifier("ds1") @Autowired DataSource dataSource; @Bean(name = "sqlSessionFactory1") public SqlSessionFactory sqlSessionFactory1() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); factoryBean.setMapperLocations(resolver.getResources("classpath:mappers/db1/*.xml")); factoryBean.setTypeAliasesPackage("cn.yjxxclub.demo.datasource.model"); return factoryBean.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate1() throws Exception { SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory1()); // 使用上面配置的Factory return template; }}
/** * Author: Starry.Teng * Email: tengxing7452@163.com * Date: 17-11-1 * Time: 下午9:26 * Describe: MybatisDb2 Config */@Configuration@MapperScan(basePackages = {"cn.yjxxclub.demo.datasource.dao.db2"}, sqlSessionFactoryRef = "sqlSessionFactory2")public class MybatisDb2Config { @Qualifier("ds2") @Autowired DataSource dataSource; @Bean(name = "sqlSessionFactory2") public SqlSessionFactory sqlSessionFactory2() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); factoryBean.setMapperLocations(resolver.getResources("classpath:mappers/db2/*.xml")); factoryBean.setTypeAliasesPackage("cn.yjxxclub.demo.datasource.model"); return factoryBean.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate2() throws Exception { SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory2()); return template; }}
编写Dao和Mapper
Mapper.java和mapper.xml在basePackages和classpath对应放置即可,和springboot整合Mybtis一样,这里就不说了,然后正常启动即可。代码在此:https://github.com/tengxing/Multiple-dataSources
数据源动态切换
数据源注册
/** * Author: Starry.Teng * Email: tengxing7452@163.com * Date: 17-11-1 * Time: 下午9:14 * Describe: DataSource Config */@Configurationpublic class DataSourceConfig { @Autowired Environment env; @Bean(name = "ds1") public DataSource dataSource1() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(env.getProperty("spring.datasource.db1.url")); dataSource.setUsername(env.getProperty("spring.datasource.db1.username")); dataSource.setPassword(env.getProperty("spring.datasource.db1.password")); dataSource.setDriverClassName(env.getProperty("spring.datasource.db1.driver-class-name")); return dataSource; } @Bean(name = "ds2") public DataSource dataSource2() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(env.getProperty("spring.datasource.db2.url")); dataSource.setUsername(env.getProperty("spring.datasource.db2.username")); dataSource.setPassword(env.getProperty("spring.datasource.db2.password")); dataSource.setDriverClassName(env.getProperty("spring.datasource.db2.driver-class-name")); return dataSource; } @Bean(name = "dynamicDS1")//注意这个bean是mybatis的sqlSessionFacatory所管理的dataSource public DataSource dataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); // 默认数据源 dynamicDataSource.setDefaultTargetDataSource(dataSource1()); // 配置多数据源 Map<Object, Object> dsMap = new HashMap(5); dsMap.put("ds1", dataSource1()); dsMap.put("ds2", dataSource2()); dynamicDataSource.setTargetDataSources(dsMap); return dynamicDataSource; }}
动态数据源编写
需要继承AbstractRoutingDataSource类
/** * Author: http://blog.csdn.net/neosmith/article/details/61202084 * Date: 17-11-2 * Time: 下午2:56 * Describe: 动态数据源 */public class DynamicDataSource extends AbstractRoutingDataSource { private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class); @Override protected Object determineCurrentLookupKey() { log.debug("数据源为{}", DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); }}
编写DataSourceContextHolder
/** * Author: http://blog.csdn.net/neosmith/article/details/61202084 * Date: 17-11-2 * Time: 下午2:56 * Describe: DataSource ContextHolder */public class DataSourceContextHolder { public static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class); /** * 默认数据源 */ public static final String DEFAULT_DS = "ds1"; /** * 获取当前线程 */ private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 设置数据源名 public static void setDB(String dbType) { log.debug("切换到{}数据源", dbType); contextHolder.set(dbType); } // 获取数据源名 public static String getDB() { return (contextHolder.get()); } // 清除数据源名 public static void clearDB() { contextHolder.remove(); }}
咋们到时候只要调用setDB()方法即可实现数据源的切换,下面使用Aop的方式进行动态切换。
编写代理类
/** * Author: http://blog.csdn.net/neosmith/article/details/61202084 * Date: 17-11-2 * Time: 下午3:01 * Describe: 动态数据源代理类 * 逻辑:对方法@DB注解的方法进行切面换数据源操作 */@Aspect@Component@Order(value=-1) //保证该AOP在@Transactional之前执行public class DynamicDataSourceAspect { @Before("@annotation(DB)") public void beforeSwitchDS(JoinPoint point){ //获得当前访问的class Class<?> className = point.getTarget().getClass(); //获得访问的方法名 String methodName = point.getSignature().getName(); //得到方法的参数的类型 Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes(); String dataSource = DataSourceContextHolder.DEFAULT_DS; try { // 得到访问的方法对象 Method method = className.getMethod(methodName, argClass); // 判断是否存在@DS注解 if (method.isAnnotationPresent(DB.class)) { DB annotation = method.getAnnotation(DB.class); // 取出注解中的数据源名 dataSource = annotation.value(); } } catch (Exception e) { e.printStackTrace(); } // 切换数据源 DataSourceContextHolder.setDB(dataSource); } @After("@annotation(DB)") public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); }}
自定义注解
/** * Author: Starry.Teng * Email: tengxing7452@163.com * Date: 17-11-2 * Time: 下午3:00 * Describe: */@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.METHOD})public @interface DB { String value() default "ds1";}
serviceImpl
@DB("ds1") public Object getDs1(){ Singer singer = singerMapper.findByName("陈奕迅"); logger.info("/n"+singer); return null; } @DB("ds2") public Object getDs2(){ Book book = bookMapper.findById(bookMapper.list().get(0).getId()); logger.info(book+"/n"); return null; }
最后调用吧!!!项目在此:https://github.com/tengxing/DynamicDataSource
两者比较
知识点
上面的两种方式都达到了”换数据源”目的,只是实现的原理和方式不一样而已,都是优虐,还是那句话,没有最好的方法,只有在特定的环境下最适合的解决方案。
参考文章
http://blog.csdn.net/neosmith/article/details/61202084
http://www.cnblogs.com/hdwang/p/7041096.html
http://blog.csdn.net/catoop/article/details/50575038
https://github.com/zeq9069/koala/tree/master/src/main/java/org/kyrin/koala
- springBoot 动态数据源以及Mybatis多数据源
- Springboot多数据源配置--数据源动态切换
- spring mybatis 多数据源整合 动态数据源例子
- Spring Boot + Mybatis多数据源和动态数据源配置
- Spring Boot + Mybatis多数据源和动态数据源配置
- springboot + mybatis + 多数据源
- SpringBoot+Mybatis多数据源
- springboot + mybatis + 多数据源
- SpringBoot、MyBatis配置多数据源
- springboot+mybatis配置多数据源
- springboot多数据源(mybatis)
- Springboot MyBatis多数据源切换
- springboot-mybatis—多数据源
- Springboot配置Mybatis多数据源
- SpringBoot整合Mybatis多数据源
- springBoot+mybatis多数据源的配置
- Springboot MyBatis多数据源切换
- SpringBoot下配置Mybatis多数据源
- paperweekly-迁移学习
- CORBA概述
- Spring-ApplicationContext
- 移动端H5页面截图【含 domtoimage、html2canvas 】
- Idea
- springBoot 动态数据源以及Mybatis多数据源
- 在其他数都出现偶数次的数组中找到出现奇数次的数
- 怎样理解阻塞非阻塞与同步异步的区别
- 高阶函数和匿名函数
- Unity3d
- JavaSE之面向对象编程-类与对象
- Qt5.7 + VS2015 环境搭建
- 微信小程序-从零开始制作一个跑步微信小程序
- 函数的模板