您好,登錄后才能下訂單哦!
springboot中怎么實現動態數據源,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
/** * 作用:保存一個線程安全的DatabaseType容器 */ public class DatabaseContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); /** * 當需要操作數據庫前,也就是調用mapper.c/r/u/d方法前,可以調用該方法 * 該方法的作用是設置需要連接的數據庫 * 由于是線程安全,如果一個新的controller連接請求,在操作數據庫前沒有顯式的調用該方法,則get到的databaseType將會為null * 但這并不影響數據庫的操作,因為在數據源的設置中已經設置了默認的數據源 * 當在同一個線程中(也就是本系統controller的同一個請求處理中),如果該方法被調用過 * 則后面的數據庫操作,也就是mapper.c/r/u/d的時,get到的都是set好的數據源,除非再次顯式的調用這個set方法改變數據源 */ public static void setDatabaseType(String type) { contextHolder.set(type); } /** * 當通過mapper.c/r/u/d方法等操作數據庫時 * 該方法會自動被determineCurrentLookupKey方法調用到 * determineCurrentLookupKey是重寫了Spring里的AbstractRoutingDataSource類的determineCurrentLookupKey方法 * * @see DynamicDataSource */ public static String getDatabaseType() { return contextHolder.get(); } } import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; 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.env.Environment; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * 數據源工具類 */ @Configuration @Slf4j public class DataSourceUtil { @Autowired private Environment env; //默認數據源 private DataSource defaultDataSource; //用戶自定義數據源 private Map<String, DataSource> slaveDataSources = new HashMap<>(); /** * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource */ @Bean @Primary public DynamicDataSource dataSource() throws Exception { initDefaultDataSource(); initSlaveDataSources(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("", defaultDataSource); targetDataSources.putAll(slaveDataSources); DynamicDataSource dataSource = new DynamicDataSource(); dataSource.setDefaultTargetDataSource(defaultDataSource);// 該方法是AbstractRoutingDataSource的方法,默認數據源 dataSource.setTargetDataSources(targetDataSources);// 該方法是AbstractRoutingDataSource的方法,數據源map return dataSource; } private void initDefaultDataSource() { // 讀取主數據源 Map<String, String> dsMap = new HashMap<>(); dsMap.put("driver", env.getProperty("spring.datasource.driver")); dsMap.put("url", env.getProperty("spring.datasource.url")); dsMap.put("username", env.getProperty("spring.datasource.username")); dsMap.put("password", env.getProperty("spring.datasource.password")); defaultDataSource = buildDataSource(dsMap); } private void initSlaveDataSources() { // 讀取配置文件獲取更多數據源 String dsPrefixs = env.getProperty("slave.datasource.names"); for (String dsPrefix : dsPrefixs.split(",")) { // 多個數據源 Map<String, String> dsMap = new HashMap<>(); dsMap.put("driver", env.getProperty("slave.datasource." + dsPrefix + ".driver")); dsMap.put("url", env.getProperty("slave.datasource." + dsPrefix + ".url")); dsMap.put("username", env.getProperty("slave.datasource." + dsPrefix + ".username")); dsMap.put("password", env.getProperty("slave.datasource." + dsPrefix + ".password")); DataSource ds = buildDataSource(dsMap); slaveDataSources.put(dsPrefix, ds); } } //指定默認數據源(springboot2.0默認數據源是hikari如何想使用其他數據源可以自己配置) private static final String DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource"; private DataSource buildDataSource(Map<String, String> dataSourceMap) { try { Object type = dataSourceMap.get("type"); if (type == null) { type = DATASOURCE_TYPE_DEFAULT;// 默認DataSource } log.debug("data source type:{}", type); Class<? extends DataSource> dataSourceType; dataSourceType = (Class<? extends DataSource>) Class.forName((String) type); String driverClassName = dataSourceMap.get("driver"); String url = dataSourceMap.get("url"); String username = dataSourceMap.get("username"); String password = dataSourceMap.get("password"); // 自定義DataSource配置 DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url) .username(username).password(password).type(dataSourceType); return factory.build(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } } import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 動態數據源(需要繼承AbstractRoutingDataSource) */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DatabaseContextHolder.getDatabaseType(); } } @Value("#{'${slave.datasource.names}'.split(',')}") private List<String> dsNameList; public int monitor() { // 默認數據源 if (heartBeatDatabase(Strings.EMPTY) == 0) isError = true; // 其他數據源 for (String dsName : dsNameList) { if (heartBeatDatabase(dsName) == 0) isError = true; } // 出現異常 if (isError) { isError = false; return 0; } return 1; } private int heartBeatDatabase(String dsName) { try { DatabaseContextHolder.setDatabaseType(dsName); return monitorDao.select(); } catch (Exception e) { log.error("heartbeat error!"); try { sendMail(dsName); } catch (MessagingException e1) { log.error("send mail error!", e); } } return 0; } # mysql配置 spring.datasource.url=jdbc:mysql://130.51.23.249:3306/vacdb01?useUnicode=true&characterEncoding=utf-8 spring.datasource.username=root1 spring.datasource.password= spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # ds1,ds2等其他數據源,記得不要漏!否則下面配置了也是白配。 slave.datasource.names=ds1,ds2,ds3 # ds1 slave.datasource.ds1.driver=com.mysql.cj.jdbc.Driver slave.datasource.ds1.url=jdbc:mysql://130.51.23.249:3306/flowable?useSSL=false slave.datasource.ds1.username=flowable slave.datasource.ds1.password= # ds2 slave.datasource.ds2.driver=com.mysql.cj.jdbc.Driver slave.datasource.ds2.url=jdbc:mysql://132.120.2.134:3300/motor?useSSL=false slave.datasource.ds2.username=motor slave.datasource.ds2.password= # ds3 slave.datasource.ds3.driver=com.mysql.cj.jdbc.Driver slave.datasource.ds3.url=jdbc:mysql://130.51.23.249:8066/VACDB?useUnicode=true&characterEncoding=utf-8 slave.datasource.ds3.username=vac slave.datasource.ds3.password=
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。