<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
但是在實際業務場景中,資料量迅速增長,一個庫一個表已經滿足不了我們的需求的時候,我們就會考慮分庫分表的操作,在springboot中如何實現多資料來源,動態資料來源切換,讀寫分離等操作。 當你看到這篇檔案那麼你幸運了,下面直接提供終極通用版程式碼
如果是非Mybaitis的那麼可以進行參照,原理都差不多
spring: datasource: default-db-key: voidme multi-db: - voidme: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root url: jdbc:mysql://192.168.42.153:3306/voidme?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useSSL=false - xcdef: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root url: jdbc:mysql://192.168.42.153:3306/xcdef?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useSSL=false mybatis: #1.classpath:只會到你的classes路徑中查詢找檔案。 #2.classpath*:不僅會到classes路徑,還包括jar檔案中(classes路徑)進行查詢。 mapper-locations: classpath*:/mapper/**/*Mapper.xml # mapper對映檔案位置 type-aliases-package: com.**.entity # 實體類所在的位置 configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #用於控制檯列印sql語句 map-underscore-to-camel-case: true #開啟將帶有下劃線的表欄位 對映為駝峰格式的實體類屬性
這個類用於獲取資料來源的(核心)
package com.dynamicdatadource.dynamic; import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Value("${spring.datasource.default-db-key}") private String defaultDbKey; @Override protected Object determineCurrentLookupKey() { String currentDb = DynamicDataSourceService.currentDb(); if (currentDb == null) { return defaultDbKey; } return currentDb; } }
這個類是資料來源切換工具,我們做了執行緒隔離了所以不用擔心多執行緒資料來源會混亂的問題
package com.dynamicdatadource.dynamic; import com.application.ApplicationContextProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.jdbc.DataSourceBuilder; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; public class DynamicDataSourceService { private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceService.class); private static final Map<Object, Object> dataSources = new HashMap<>(); private static final ThreadLocal<String> dbKeys = ThreadLocal.withInitial(() -> null); /** * 動態新增一個資料來源 * * @param name 資料來源的key * @param dataSource 資料來源物件 */ public static void addDataSource(String name, DataSource dataSource) { DynamicDataSource dynamicDataSource = ApplicationContextProvider.getApplicationContext().getBean(DynamicDataSource.class); dataSources.put(name, dataSource); dynamicDataSource.setTargetDataSources(dataSources); dynamicDataSource.afterPropertiesSet(); log.info("新增了資料來源:{}",name); } /** * @param name 資料來源的key * @param driverClassName 驅動 * @param url 資料庫連線地址 * @param username 資料庫賬戶 * @param password 資料庫密碼 */ public static void addDataSource(String name, String driverClassName,String url,String username,String password) { DataSourceBuilder<?> builder = DataSourceBuilder.create(); builder.driverClassName(driverClassName); builder.username(username); builder.password(password); builder.url(url); addDataSource(name,builder.build()); log.info("新增了資料來源:{}",name); } /** * 切換資料來源 */ public static void switchDb(String dbKey) { dbKeys.set(dbKey); } /** * 重置資料來源(切換為預設的資料來源) */ public static void resetDb() { dbKeys.remove(); } /** * 獲取當前資料來源的key */ public static String currentDb() { return dbKeys.get(); } }
將資料來源設定到springboot中和初始化Mybaitis設定
package com.dynamicdatadource.dynamic; import lombok.Data; import org.apache.ibatis.logging.Log; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import java.io.IOException; import java.util.HashMap; import java.util.Map; @Configuration @ConfigurationProperties(prefix = "mybatis") @Data public class DynamicDataSourceConfig { private String mapperLocations; private String typeAliasesPackage; @Data public class MybatisConfiguration{ private String logImpl; private boolean mapUnderscoreToCamelCase; } private MybatisConfiguration configuration=new MybatisConfiguration(); /** * 動態資料來源 */ @Bean public DynamicDataSource dynamicDataSource() { DynamicDataSource dataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); dataSource.setTargetDataSources(targetDataSources); return dataSource; } /** * 對談工廠Mybaitis */ @Bean public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException, ClassNotFoundException { org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(this.configuration.isMapUnderscoreToCamelCase()); //開啟駝峰命名 configuration.setLogImpl((Class<? extends Log>) Class.forName(this.configuration.getLogImpl())); //控制檯列印sql紀錄檔 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dynamicDataSource()); sqlSessionFactoryBean.setConfiguration(configuration); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations)); sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage); return sqlSessionFactoryBean; } /** * 事務管理器 */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } }
package com.dynamicdatadource.config; import com.dynamicdatadource.dynamic.DynamicDataSourceService; import lombok.Data; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.sql.DataSource; import java.util.List; import java.util.Map; import java.util.Set; @Component @Data @ConfigurationProperties(prefix = "spring.datasource") public class YmlDataSourceProvider { private List<Map<String, DataSourceProperties>> multiDb; private DataSource buildDataSource(DataSourceProperties prop) { DataSourceBuilder<?> builder = DataSourceBuilder.create(); builder.driverClassName(prop.getDriverClassName()); builder.username(prop.getUsername()); builder.password(prop.getPassword()); builder.url(prop.getUrl()); return builder.build(); } public void initDataSource() { multiDb.forEach(map -> { Set<String> keys = map.keySet(); keys.forEach(key -> { DataSourceProperties properties = map.get(key); DataSource dataSource = buildDataSource(properties); DynamicDataSourceService.addDataSource(key, dataSource); }); }); } //在建構函式之後執行 @PostConstruct public void init() { initDataSource(); } }
package com.dynamicdatadource.aop; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD,ElementType.TYPE})//作用:方法和類 @Retention(RetentionPolicy.RUNTIME) public @interface DynamicDataSourceAnno { String key() default ""; }
package com.dynamicdatadource.aop; import com.dynamicdatadource.dynamic.DynamicDataSourceService; import org.apache.commons.lang.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; // 用於單獨的請求或者類進行切換資料庫 @Aspect @Component public class DynamicDataSourceAspect { @Pointcut("@annotation(com.dynamicdatadource.aop.DynamicDataSourceAnno)") public void dynamicDataSourceAnno() { } @Around("dynamicDataSourceAnno()") public Object DynamicDataSourceAspectAroundAnno(ProceedingJoinPoint joinPoint) { Object object = null; try { MethodSignature signature = (MethodSignature)joinPoint.getSignature(); DynamicDataSourceAnno dynamicDataSourceAnno = signature.getMethod().getAnnotation(DynamicDataSourceAnno.class); String key = dynamicDataSourceAnno.key(); if (StringUtils.isNotBlank(key)) { //切換為指定資料庫 DynamicDataSourceService.switchDb(key); } object = joinPoint.proceed(); } catch (Throwable e) { e.printStackTrace(); }finally { //還原為預設設定 DynamicDataSourceService.resetDb(); } return object; } // 還可以擴充套件包路徑切換 }
執行程式之後,就會將資料來源加入到資料來源列表中了
從資料庫中將設定資訊查詢出來,然後動態新增到資料來源列表中
package com.dao.config; import com.dao.DatasourceDao; import com.dynamicdatadource.aop.DynamicDataSourceAnno; import com.dynamicdatadource.dynamic.DynamicDataSourceService; import com.entity.DataSourceEneity; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.sql.DataSource; import java.util.List; //從資料庫中查詢出全部的資料來源,新增到資料來源容器中 /** * 表結構如下: * * CREATE TABLE `t_datasource` ( * `id` int(11) NOT NULL, * `key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '繫結的key,用於資料來源的切換', * `url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '資料庫連線地址', * `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '資料庫使用者名稱', * `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '資料庫密碼', * `driverClassName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '資料庫驅動', * `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '資料庫型別: mysql ,oracle,..', * `state` int(2) NOT NULL COMMENT '是否可用: 1可用 ,2不可用', * PRIMARY KEY (`id`), * UNIQUE KEY `key` (`key`) * ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; * * 上表要放入到預設資料來源中的資料庫裡才行 */ @Component public class MysqlDataSourceInitialize implements ApplicationRunner { @Autowired private DatasourceDao datasourceDao; //專案啟動後執行初始化資料來源 @Override public void run(ApplicationArguments args) throws Exception { try { List<DataSourceEneity> dataSources = datasourceDao.getDataSources(); for (DataSourceEneity dataSource : dataSources) { DynamicDataSourceService.addDataSource(dataSource.getKey(),dataSource.getDataSource()); } } catch (Exception e) { e.printStackTrace(); } } }
@Data public class DataSourceEneity { private int id; private String key; private String url; private String username; private String password; private String driverClassName; private String type; private int state; public DataSource getDataSource() { DataSourceBuilder<?> builder = DataSourceBuilder.create(); builder.driverClassName(driverClassName); builder.username(username); builder.password(password); builder.url(url); return builder.build(); } }
到此這篇關於SpringBoot多資料來源切換實現的文章就介紹到這了,更多相關SpringBoot多資料來源切換內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45