springboot mybatis多数据源的两种整合方法
它能收集并整合各种来源的数据 #生活技巧# #领导力技巧# #决策支持系统#
一个项目使用多个数据库(无论是主从复制--读写分离还是分布式数据库结构)的重要性变得越来越明显,整合的多数据源有两种方式:分包和aop。
分包以分包的方式来区分不同的数据源,也就是不同的包,连接不同的数据库。
1、application的数据源配置
##数据源1
##driverClassName driver-class-name
spring.datasource.test1.driver-class-name: com.mysql.jdbc.Driver
spring.datasource.test1.jdbc-url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.test1.username: root
spring.datasource.test1.password: root
#数据源2
spring.datasource.test2.driver-class-name: com.mysql.jdbc.Driver
spring.datasource.test2.jdbc-url: jdbc:mysql://127.0.0.1:3306/springboot1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.test2.username: root
spring.datasource.test2.password: root
2、数据源配置类
DataSource1Config.java
@Configuration
@MapperScan(basePackages = "com.jessDl.dataSource1",
sqlSessionTemplateRef = "test1SqlSessionTemplate")
public class DataSource1Config {
@Bean(name = "test1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test1")
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(
@Qualifier("test1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
getResources("classpath:mybatis/mapper/test1/*.xml"));
return bean.getObject();
}
@Bean(name = "test1TransactionManager")
public DataSourceTransactionManager testTransactionManager(
@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
这里我们要对mybatis sqlSession有一些认识和理解,mybatis进行持久化时有几个重要的类:
(1)SqlSessionFactoryBuilder: build方法创建SqlSessionFactory实例。
(2)SqlSessionFactory: 创建SqlSession实例的工厂。
(3)SqlSession: 用于持久化操作的对象,类似于jdbc中的Connection。
(4)SqlSessionTemplate: 持久化层访问模板化的工具,线程安全,可通过构造参数或依赖注入。
一层层的注入,先创建DataSource,再创建SqlSessionFactory,再创建事务,最后包装到SqlSessionTemplate中。其中需要制定分库的mapper文件地址,以及分库dao层
DataSource2Config.java
@Configuration
@MapperScan(basePackages = "com.jessDl.dataSource2", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class DataSource2Config {
@Bean(name = "test2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test2")
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "test2TransactionManager")
public DataSourceTransactionManager testTransactionManager(@Qualifier("test2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
dataSource1操作数据源1,dataSource2操作数据源2. dao喜忧参半和xml需要按照库来分在不同的目录。
aop方式1、AbstractRoutingDataSource
实现数据源切换的功能就是自定义一个类扩展AbstractRoutingDataSource抽象类,而AbstractRoutingDataSource又继承于AbstractDataSource,AbstractDataSource实现了统一的DataSource接口。
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
这里我们编写一个根据当前线程来选择数据源,然后通过AOP拦截特定的注解。
配置的多个数据源会放在AbstractRoutingDataSource的targetDataSources和defaultTargetDataSource中。
AbstractRoutingDataSource的getConnection()的方法的时候,先调用determinTargetDataSource()方法返回DataSource在进行getConnection()
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}
很简单就可以看到,我们通过自己实现的determineCurrentLookupKey()方法返回了lookupKey,根据配置的key就获取到对应的数据源达到切换的功能。
2、yml配置
spring:
datasource:
druid:
db1:
url: jdbc:mysql://localhost:3306/eboot
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
maxActive: 20
db2:
url: jdbc:oracle:thin:@192.168.136.222:ORCL
username: sa
password: sa123456
driver-class-name: oracle.jdbc.OracleDriver
initialSize: 5
minIdle: 5
maxActive: 20
db3:
url: jdbc:oracle:thin:@192.168.136.223:ORCL
username: sb
password: sb123456
driver-class-name: oracle.jdbc.OracleDriver
initialSize: 5
minIdle: 5
maxActive: 20
3、pom依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
4、把数据源放入DruidDataSource中
@EnableTransactionManagement
@Configuration
public class DataSourceConfig {
private static final Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);
@Bean(name="db1")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1")
public DataSource db1(){
return DruidDataSourceBuilder.create().build();
}
@Bean(name="db2")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2")
public DataSource db2(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
@Qualifier("db2") DataSource db2){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object,Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.PG1.getName(),db1);
targetDataSources.put(DataSourceType.PG2.getName(),db2);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(db1);
return dynamicDataSource;
}
}
5、为了规范,DataSourceType枚举类
public enum DataSourceType {
PG1("pg1"),
PG2("pg2");
private String name;
DataSourceType(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
6、动态数据决策类
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey(){
return BaseContextHandler.get(EvaConstants.DATA_SOURCE);
}
}
7.ThreadLocal类
public class BaseContextHandler {
private final static Logger logger = LoggerFactory.getLogger(BaseContextHandler.class);
public static ThreadLocal<Map<String,Object>> threadLocal = new ThreadLocal<>();
public static void set(String key,Object value){
Map<String,Object> map = threadLocal.get();
if(map==null){
map = new HashMap<String,Object>();
threadLocal.set(map);
}
map.put(key,value);
}
public static Object get(String key){
Map<String,Object> map = threadLocal.get();
if(map==null){
map = new HashMap<String,Object>();
threadLocal.set(map);
}
return map.get(key);
}
public static void remove(){
threadLocal.remove();
}
}
8、AOP
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetDataSource {
DataSourceType value() default DataSourceType.PG1;
}
@Aspect
@Order(2)
@Component
public class DataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
@Before("@annotation(targetDataSource)")
public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource){
DataSourceType dbType = targetDataSource.value();
if(dbType.equals(DataSourceType.PG1)){
BaseContextHandler.set(EvaConstants.DATA_SOURCE,DataSourceType.PG1.getName());
}else{
BaseContextHandler.set(EvaConstants.DATA_SOURCE,DataSourceType.PG2.getName());
}
}
@After("@annotation(targetDataSource)")
public void clearDataSource(JoinPoint joinPoint,TargetDataSource targetDataSource){
BaseContextHandler.remove();
}
}
这样在dao层只需要这样
@TargetDataSource(value= DataSourceType.PG2)
int getSeq(@Param("seqName")String seqName);
网址:springboot mybatis多数据源的两种整合方法 https://www.yuejiaxmz.com/news/view/714901
相关内容
【SpringBoot】整合Mybatis【附源码】计算机毕业设计健康食谱推荐分享系统(java+springboot+mysql+mybatis+论文)
Springboot减重系统g0d5s(程序+源码+数据库+调试部署+开发环境)
Mybatis
【含文档】基于Springboot+Vue的二手书籍交易系统(含源码+数据库+lw)
Springboot+ssm(Spring+SpringMVC+MyBatis)旧物置换网站
Springboot健身会馆预约管理系统o14kl(程序+源码+数据库+调试部署+开发环境)
Springboot家居产品的进销存系统dgo68(程序+源码+数据库+调试部署+开发环境)
Springboot家具商城系统h4q2o(程序+源码+数据库+调试部署+开发环境)
Springboot健康管理系统1ii1u(程序+源码+数据库+调试部署+开发环境)