springboot实现多数据源连接
application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource renewdb.driver-class-name=com.mysql.jdbc.Driver renewdb.name=test renewdb.username=test renewdb.password=test renewdb.jdbc-url=jdbc:mysql://localhost/renewDB?useSSL=false&allowMultiQueries=true renewdb.max-active=20 renewdb.validation-query=SELECT 1 FROM DUAL renewdb.initial-size=10 renewdb.max-wait=60000 channeldb.driver-class-name=com.mysql.jdbc.Driver channeldb.name=test channeldb.username=test channeldb.password=test channeldb.jdbc-url=jdbc:mysql://localhost:3306/channel_mgt_tst?useSSL=false&allowMultiQueries=true channeldb.max-active=20 channeldb.validation-query=SELECT 1 FROM DUAL channeldb.initial-size=10 channeldb.max-wait=60000
1.注解实现
DataSourceConfig.java
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * 多数据源配置类 */ @Configuration public class DataSourceConfig { //数据源1 @Bean(name = "renewdb") @ConfigurationProperties(prefix = "renewdb") // application.properteis中对应属性的前缀 public DataSource renewdb() { return DataSourceBuilder.create().build(); } //数据源2 @Bean(name = "channeldb") @ConfigurationProperties(prefix = "channeldb") // application.properteis中对应属性的前缀 public DataSource channeldb() { return DataSourceBuilder.create().build(); } /** * 动态数据源: 通过AOP在不同数据源之间动态切换 * @return */ @Primary @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); // 默认数据源 dynamicDataSource.setDefaultTargetDataSource(renewdb()); // 配置多数据源 Map<Object, Object> dsMap = new HashMap(); dsMap.put("renewdb", renewdb()); dsMap.put("channeldb", channeldb()); dynamicDataSource.setTargetDataSources(dsMap); return dynamicDataSource; } /** * 配置@Transactional注解事物 * @return */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } }
DataSourceContextHolder.java
public class DataSourceContextHolder { /** * 默认数据源 */ public static final String DEFAULT_DS = "renewdb"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 设置数据源名 public static void setDB(String dbType) { contextHolder.set(dbType); } // 获取数据源名 public static String getDB() { return (contextHolder.get()); } // 清除数据源名 public static void clearDB() { contextHolder.remove(); } }
DS.java
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义注解 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface DS { String value() default "renewdb"; }
DynamicDataSource.java
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import java.util.logging.Logger; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { System.out.println("数据源为=======>" + DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); } @Override public Logger getParentLogger() { return null; } }
DynamicDataSourceAspect.java
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * AOP的方式实现数据源动态切换。 */ @Aspect @Component public class DynamicDataSourceAspect { @Before("@annotation(DS)") 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(DS.class)) { DS annotation = method.getAnnotation(DS.class); // 取出注解中的数据源名 dataSource = annotation.value(); } } catch (Exception e) { e.printStackTrace(); } // 切换数据源 DataSourceContextHolder.setDB(dataSource); } @After("@annotation(DS)") public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); } }
2.分包实现
ChannelDBConfig.java
import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; @Configuration @MapperScan(basePackages = "com.zjrenew.dao.channeldb", sqlSessionFactoryRef = "channelSqlSessionFactory") public class ChannelDBConfig { @Bean("channelDataSource") @ConfigurationProperties(prefix = "channeldb") public DataSource getDb1DataSource(){ return DataSourceBuilder.create().build(); } @Bean("channelSqlSessionFactory") public SqlSessionFactory db1SqlSessionFactory(@Qualifier("channelDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/channeldb/*.xml")); return bean.getObject(); } @Bean("db2SqlSessionTemplate") public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("channelSqlSessionFactory") SqlSessionFactory sqlSessionFactory){ return new SqlSessionTemplate(sqlSessionFactory); } }
RenewDBConfig.java
import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; @Configuration @MapperScan(basePackages = "com.zjrenew.dao.renewdb", sqlSessionFactoryRef = "renewdbSqlSessionFactory") public class RenewDBConfig { @Primary // 表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源) @Bean("renewdbDataSource") @ConfigurationProperties(prefix = "renewdb") //读取application.yml中的配置参数映射成为一个对象 public DataSource getrenewdbDataSource(){ return DataSourceBuilder.create().build(); } @Primary @Bean("renewdbSqlSessionFactory") public SqlSessionFactory renewdbSqlSessionFactory(@Qualifier("renewdbDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // mapper的xml形式文件位置必须要配置,不然将报错:no statement (这种错误也可能是mapper的xml中,namespace与项目的路径不一致导致) bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/renewdb/*.xml")); return bean.getObject(); } @Primary @Bean("db1SqlSessionTemplate") public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("renewdbSqlSessionFactory") SqlSessionFactory sqlSessionFactory){ return new SqlSessionTemplate(sqlSessionFactory); } }
浙公网安备 33010602011771号