【springboot整合多数据源】
生活随笔
收集整理的這篇文章主要介紹了
【springboot整合多数据源】
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
springboot整合多數(shù)據(jù)源
- 配置多數(shù)據(jù)
- application.yaml
- 動(dòng)態(tài)路由數(shù)據(jù)源
- 數(shù)據(jù)源上下文管理
- 數(shù)據(jù)源切面
- MybatisPlusConfig配置
- 自定義方法注入器
- 擴(kuò)展配置,幫助我們批量更新、新增等操作
- RootMapper
- InsertBatchMethod
- UpdateBatchMethod
配置多數(shù)據(jù)
application.yaml
spring:application:name: erp9-synaop:proxy-target-class: trueauto: truemain:allow-bean-definition-overriding: truedatasource:erp9:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.80.211:3306/1231?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=trueusername: b1b_goodspassword: asdadinitialSize: 10minIdle: 10maxActive: 80type: com.alibaba.druid.pool.DruidDataSourcerate:driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriverurl: jdbc:sqlserver://101.200.55.149:6522;Databasename=sacsacusername: ascacpassword: 121sadsinitialSize: 5minIdle: 5maxActive: 40type: com.alibaba.druid.pool.DruidDataSource # 日志配置 mybatis-plus:mapper-locations: classpath:xml/**/*Mapper.xmltypeAliasesPackage: com.yuanda.erp9.syn.entityconfiguration:map-underscore-to-camel-case: true# console輸出日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl動(dòng)態(tài)路由數(shù)據(jù)源
package com.yuanda.erp9.syn.config;import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 動(dòng)態(tài)路由數(shù)據(jù)源*/ @Order(1) @Slf4j public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {String datasource = DynamicDataSourceContextHolder.getDataSourceKey();super.setDefaultTargetDataSource(datasource);log.debug("使用數(shù)據(jù)源 {}", datasource);return datasource;} }數(shù)據(jù)源上下文管理
package com.yuanda.erp9.syn.config;import com.yuanda.erp9.syn.contant.DatabaseGlobal; import java.util.ArrayList; import java.util.Collection; import java.util.List;/*** @ClassName DynamicDataSourceContextHolder* @Description 數(shù)據(jù)上下文管理* @Date 2022/12/15* @Author myq*/ public class DynamicDataSourceContextHolder {/*** 實(shí)際上就是開(kāi)啟多個(gè)線程,每個(gè)線程進(jìn)行初始化一個(gè)數(shù)據(jù)源*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>() {/*** 將 master 數(shù)據(jù)源的 key作為默認(rèn)數(shù)據(jù)源的 key*/@Overrideprotected String initialValue() {return DatabaseGlobal.erp9;}};/*** 數(shù)據(jù)源的 key集合,用于切換時(shí)判斷數(shù)據(jù)源是否存在*/public static List<Object> dataSourceKeys = new ArrayList<Object>();/*** 切換數(shù)據(jù)源** @param key*/public static void setDataSourceKey(String key) {CONTEXT_HOLDER.set(key);}/*** 獲取數(shù)據(jù)源** @return*/public static String getDataSourceKey() {return CONTEXT_HOLDER.get();}/*** 重置數(shù)據(jù)源*/public static void clearDataSourceKey() {CONTEXT_HOLDER.remove();}/*** 判斷是否包含數(shù)據(jù)源** @param key 數(shù)據(jù)源key* @return*/public static boolean containDataSourceKey(String key) {return dataSourceKeys.contains(key);}/*** 添加數(shù)據(jù)源keys** @param keys* @return*/public static boolean addDataSourceKeys(Collection<? extends Object> keys) {return dataSourceKeys.addAll(keys);} }數(shù)據(jù)源切面
package com.yuanda.erp9.syn.config;import com.yuanda.erp9.syn.contant.DatabaseGlobal; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component;@Component @Order(value = -100) @Aspect @Slf4j public class DataSourceAspect {@Pointcut("execution( * com.yuanda.erp9.syn.service.erp9.impl..*.*(..))")private void erp9Aspect() {}@Pointcut("execution(* com.yuanda.erp9.syn.service.rate.impl..*.*(..))")private void rateAspect() {}@Before("erp9Aspect()")public void cyz() {log.debug("切換到{} 數(shù)據(jù)源...", DatabaseGlobal.erp9);DynamicDataSourceContextHolder.setDataSourceKey(DatabaseGlobal.erp9);}@Before("rateAspect()")public void pveStandard() {log.debug("切換到{} 數(shù)據(jù)源...", DatabaseGlobal.rate);DynamicDataSourceContextHolder.setDataSourceKey(DatabaseGlobal.rate);} }MybatisPlusConfig配置
package com.yuanda.erp9.syn.config;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.alibaba.druid.wall.WallConfig; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import com.yuanda.erp9.syn.contant.DatabaseGlobal; import com.yuanda.erp9.syn.core.CustomizedSqlInjector; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.type.JdbcType; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; 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 org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map;/*** @ClassName MybatisPlusConfig* @Description 配置文件-自定義sql注入器* @Date 2022/11/16* @Author myq*/ @MapperScan({"com.yuanda.erp9.syn.mapper.erp9", "com.yuanda.erp9.syn.mapper.rate"}) @Configuration @EnableTransactionManagement @ConfigurationProperties(prefix = "mybatis-plus") public class MybatisPlusConfig {/*** 可以寫死 可以沖配置文件中讀取*/private Class logImpl;static {System.setProperty("druid.mysql.usePingMethod","false");}@Beanpublic CustomizedSqlInjector customizedSqlInjector() {return new CustomizedSqlInjector();}/*** 這個(gè)bean可以幫助我們一次執(zhí)行多條dml語(yǔ)句,沒(méi)有哦這個(gè)配置會(huì)出現(xiàn)執(zhí)行多次sql會(huì)出現(xiàn)報(bào)錯(cuò)。*/@Beanpublic WallConfig wallConfig() {WallConfig config = new WallConfig();config.setMultiStatementAllow(true);//允許一次執(zhí)行多條語(yǔ)句config.setNoneBaseStatementAllow(true);//允許非基本語(yǔ)句的其他語(yǔ)句return config;}@Bean(name = DatabaseGlobal.erp9)@ConfigurationProperties(prefix = "spring.datasource.erp9")public DataSource erp9() {return DruidDataSourceBuilder.create().build();}@Bean(name = DatabaseGlobal.rate)@ConfigurationProperties(prefix = "spring.datasource.rate")public DataSource rate() {return DruidDataSourceBuilder.create().build();}/*** 動(dòng)態(tài)數(shù)據(jù)源配置** @return*/@Bean@Primarypublic DataSource multipleDataSource(@Qualifier(DatabaseGlobal.erp9) DataSource erp9DataSource,@Qualifier(DatabaseGlobal.rate) DataSource rateDataSource) {DynamicDataSource dynamicDataSource = new DynamicDataSource();Map<Object, Object> targetDataSources = new HashMap<Object, Object>();targetDataSources.put(DatabaseGlobal.erp9, erp9DataSource);targetDataSources.put(DatabaseGlobal.rate, rateDataSource);dynamicDataSource.setTargetDataSources(targetDataSources);// 程序默認(rèn)數(shù)據(jù)源,這個(gè)要根據(jù)程序調(diào)用數(shù)據(jù)源頻次,經(jīng)常把常調(diào)用的數(shù)據(jù)源作為默認(rèn)dynamicDataSource.setDefaultTargetDataSource(erp9DataSource);return dynamicDataSource;}@Bean("sqlSessionFactory")public SqlSessionFactory sqlSessionFactory(@Qualifier(DatabaseGlobal.erp9) DataSource erp9DataSource,@Qualifier(DatabaseGlobal.rate) DataSource rateDataSource) throws Exception {MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();// 多數(shù)據(jù)源必須設(shè)置sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:xml/**/*Mapper.xml"));sqlSessionFactory.setDataSource(multipleDataSource(erp9DataSource, rateDataSource));MybatisConfiguration configuration = new MybatisConfiguration();configuration.setJdbcTypeForNull(JdbcType.NULL);configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(false);configuration.setLogImpl(logImpl);sqlSessionFactory.setGlobalConfig(globalConfiguration());sqlSessionFactory.setConfiguration(configuration);return sqlSessionFactory.getObject();}@Beanpublic GlobalConfig globalConfiguration() {GlobalConfig conf = new GlobalConfig();// 自定義的注入需要在這里進(jìn)行配置conf.setSqlInjector(customizedSqlInjector());return conf;}}自定義方法注入器
package com.yuanda.erp9.syn.core;import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import org.springframework.stereotype.Component;import java.util.List;/*** 自定義方法SQL注入器*/ @Component public class CustomizedSqlInjector extends DefaultSqlInjector {/*** 如果只需增加方法,保留mybatis plus自帶方法,* 可以先獲取super.getMethodList(),再添加add*/@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {List<AbstractMethod> methodList = super.getMethodList(mapperClass);## 這倆是mybatisPlus實(shí)現(xiàn)的批量更新操作 也可以注釋掉methodList.add(new InsertBatchMethod());methodList.add(new UpdateBatchMethod());return methodList;} }擴(kuò)展配置,幫助我們批量更新、新增等操作
RootMapper
package com.yuanda.erp9.syn.core;import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.toolkit.Constants; import org.apache.ibatis.annotations.Param;import java.util.List;/*** 根Mapper,給表Mapper繼承用的,可以自定義通用方法* {@link com.baomidou.mybatisplus.core.mapper.BaseMapper}* {@link com.baomidou.mybatisplus.extension.service.IService}* {@link com.baomidou.mybatisplus.extension.service.impl.ServiceImpl}*/ public interface RootMapper<T> extends BaseMapper<T> {/*** 自定義批量插入* 如果要自動(dòng)填充,@Param(xx) xx參數(shù)名必須是 list/collection/array 3個(gè)的其中之一*/int insertBatch(@Param("list") List<T> list);/*** 自定義批量更新,條件為主鍵* 如果要自動(dòng)填充,@Param(xx) xx參數(shù)名必須是 list/collection/array 3個(gè)的其中之一*/int updateBatch(@Param("list") List<T> list);}InsertBatchMethod
package com.yuanda.erp9.syn.core;import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.keygen.NoKeyGenerator; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource;/*** 批量插入方法實(shí)現(xiàn)*/ @Slf4j public class InsertBatchMethod extends AbstractMethod {/*** insertBatch into user(id, name, age) values (1, "a", 17), (2, "b", 18);<script>insertBatch into user(id, name, age) values<foreach collection="list" item="item" index="index" open="(" separator="),(" close=")">#{item.id}, #{item.name}, #{item.age}</foreach></script>*/@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {final String sql = "<script>insert into %s %s values %s</script>";final String fieldSql = prepareFieldSql(tableInfo);final String valueSql = prepareValuesSql(tableInfo);final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);log.debug("sqlResult----->{}", sqlResult);SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);// 第三個(gè)參數(shù)必須和RootMapper的自定義方法名一致return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, new NoKeyGenerator(), null, null);}private String prepareFieldSql(TableInfo tableInfo) {StringBuilder fieldSql = new StringBuilder();fieldSql.append(tableInfo.getKeyColumn()).append(",");tableInfo.getFieldList().forEach(x -> {fieldSql.append(x.getColumn()).append(",");});fieldSql.delete(fieldSql.length() - 1, fieldSql.length());fieldSql.insert(0, "(");fieldSql.append(")");return fieldSql.toString();}private String prepareValuesSql(TableInfo tableInfo) {final StringBuilder valueSql = new StringBuilder();valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));valueSql.delete(valueSql.length() - 1, valueSql.length());valueSql.append("</foreach>");return valueSql.toString();} }UpdateBatchMethod
package com.yuanda.erp9.syn.core;import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource;/*** 批量更新方法實(shí)現(xiàn),條件為主鍵,選擇性更新*/ @Slf4j public class UpdateBatchMethod extends AbstractMethod {/*** update user set name = "a", age = 17 where id = 1;* update user set name = "b", age = 18 where id = 2;<script><foreach collection="list" item="item" separator=";">update user<set><if test="item.name != null and item.name != ''">name = #{item.name,jdbcType=VARCHAR},</if><if test="item.age != null">age = #{item.age,jdbcType=INTEGER},</if></set>where id = #{item.id,jdbcType=INTEGER}</foreach></script>*/@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {String sql = "<script>\n<foreach collection=\"list\" item=\"item\" separator=\";\">\nupdate %s %s where %s=#{%s} %s\n</foreach>\n</script>";String additional = tableInfo.isWithVersion() ? tableInfo.getVersionFieldInfo().getVersionOli("item", "item.") : "" + tableInfo.getLogicDeleteSql(true, true);String setSql = sqlSet(tableInfo.isWithLogicDelete(), false, tableInfo, false, "item", "item.");String sqlResult = String.format(sql, tableInfo.getTableName(), setSql, tableInfo.getKeyColumn(), "item." + tableInfo.getKeyProperty(), additional);log.debug("sqlResult----->{}", sqlResult);SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);// 第三個(gè)參數(shù)必須和RootMapper的自定義方法名一致return this.addUpdateMappedStatement(mapperClass, modelClass, "updateBatch", sqlSource);}}總結(jié)
以上是生活随笔為你收集整理的【springboot整合多数据源】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: bzoj-1031 字符加密Cipher
- 下一篇: 用完加速器国内的网址打不开了?