赞
踩
# 数据库访问配置
# 主数据源,默认的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url= jdbc:mysql://127.0.0.1:3306/test0?useUnicode=true&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root1234
# 更多数据源
com.pgl.edi.datasource.names=test1,test2
com.pgl.edi.datasource.test1.type=com.alibaba.druid.pool.DruidDataSource
com.pgl.edi.datasource.test1.driver-class-name=com.mysql.jdbc.Driver
com.pgl.edi.datasource.test1.url=jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=UTF-8
com.pgl.edi.datasource.test1.username=root
com.pgl.edi.datasource.test1.password=root1234
com.pgl.edi.datasource.test2.type=com.alibaba.druid.pool.DruidDataSource
com.pgl.edi.datasource.test2.driver-class-name=com.mysql.jdbc.Driver
com.pgl.edi.datasource.test2.url= jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=UTF-8
com.pgl.edi.datasource.test2.username=root
com.pgl.edi.datasource.test2.password=root1234
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM t_user
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=true
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j

- import java.util.HashMap;
- import java.util.Map;
-
- import javax.sql.DataSource;
-
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.MutablePropertyValues;
- import org.springframework.beans.PropertyValues;
- import org.springframework.beans.factory.support.BeanDefinitionRegistry;
- import org.springframework.beans.factory.support.GenericBeanDefinition;
- import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
- import org.springframework.boot.bind.RelaxedDataBinder;
- import org.springframework.boot.bind.RelaxedPropertyResolver;
- import org.springframework.context.EnvironmentAware;
- import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
- import org.springframework.core.convert.ConversionService;
- import org.springframework.core.convert.support.DefaultConversionService;
- import org.springframework.core.env.Environment;
- import org.springframework.core.type.AnnotationMetadata;
-
- /**
- *
- * 功能描述:动态数据源注册
- * 启动动态数据源请在启动类中(如Start)
- * 添加 @Import(DynamicDataSourceRegister.class)
- */
- public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
-
- private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
-
- private ConversionService conversionService = new DefaultConversionService();
- private PropertyValues dataSourcePropertyValues;
-
- // 如配置文件中未指定数据源类型,使用该默认值
- private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
-
-
- // 数据源
- private DataSource defaultDataSource;
- private Map<String, DataSource> customDataSources = new HashMap<>();
-
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
- // 将主数据源添加到更多数据源中
- targetDataSources.put("dataSource", defaultDataSource);
- DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
- // 添加更多数据源
- targetDataSources.putAll(customDataSources);
- for (String key : customDataSources.keySet()) {
- DynamicDataSourceContextHolder.dataSourceIds.add(key);
- }
-
- // 创建DynamicDataSource
- GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
- beanDefinition.setBeanClass(DynamicDataSource.class);
- beanDefinition.setSynthetic(true);
- MutablePropertyValues mpv = beanDefinition.getPropertyValues();
- mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
- mpv.addPropertyValue("targetDataSources", targetDataSources);
- registry.registerBeanDefinition("dataSource", beanDefinition);
-
- logger.info("Dynamic DataSource Registry");
- }
-
- /**
- * 创建DataSource
- *
- * @param type
- * @param driverClassName
- * @param url
- * @param username
- * @param password
- * @return
- */
- @SuppressWarnings("unchecked")
- public DataSource buildDataSource(Map<String, Object> dsMap) {
- try {
- Object type = dsMap.get("type");
- if (type == null)
- type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
-
- Class<? extends DataSource> dataSourceType;
- dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
-
- String driverClassName = dsMap.get("driver-class-name").toString();
- String url = dsMap.get("url").toString();
- String username = dsMap.get("username").toString();
- String password = dsMap.get("password").toString();
-
- DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
- .username(username).password(password).type(dataSourceType);
- return factory.build();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 加载多数据源配置
- */
- @Override
- public void setEnvironment(Environment env) {
- initDefaultDataSource(env);
- initCustomDataSources(env);
- }
-
- /**
- * 初始化主数据源
- *
- */
- private void initDefaultDataSource(Environment env) {
- // 读取主数据源
- RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
- Map<String, Object> dsMap = new HashMap<>();
- dsMap.put("type", propertyResolver.getProperty("type"));
- dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
- dsMap.put("url", propertyResolver.getProperty("url"));
- dsMap.put("username", propertyResolver.getProperty("username"));
- dsMap.put("password", propertyResolver.getProperty("password"));
-
- defaultDataSource = buildDataSource(dsMap);
-
- dataBinder(defaultDataSource, env);
- }
-
- /**
- * 为DataSource绑定更多数据
- *
- * @param dataSource
- * @param env
- */
- private void dataBinder(DataSource dataSource, Environment env) {
- RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
- // dataBinder.setValidator(new
- // LocalValidatorFactory().run(this.applicationContext));
- dataBinder.setConversionService(conversionService);
- dataBinder.setIgnoreNestedProperties(false);// false
- dataBinder.setIgnoreInvalidFields(false);// false
- dataBinder.setIgnoreUnknownFields(true);// true
- if (dataSourcePropertyValues == null) {
- Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
- Map<String, Object> values = new HashMap<>(rpr);
- // 排除已经设置的属性
- values.remove("type");
- values.remove("driver-class-name");
- values.remove("url");
- values.remove("username");
- values.remove("password");
- dataSourcePropertyValues = new MutablePropertyValues(values);
- }
- dataBinder.bind(dataSourcePropertyValues);
- }
-
- /**
- * 初始化更多数据源
- *
- */
- private void initCustomDataSources(Environment env) {
- // 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源
- RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "com.pgl.edi.datasource.");//这里写自己的配置的数据源前缀
- String dsPrefixs = propertyResolver.getProperty("names");//根据自己定义的获取数据源key
- for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
- Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
- DataSource ds = buildDataSource(dsMap);
- customDataSources.put(dsPrefix, ds);
- dataBinder(ds, env);
- }
- }
-
- }

- import java.util.ArrayList;
- import java.util.List;
-
-
- public class DynamicDataSourceContextHolder {
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
- public static List<String> dataSourceIds = new ArrayList<>();
-
- public static void setDataSourceType(String dataSourceType) {
- contextHolder.set(dataSourceType);
- }
-
- public static String getDataSourceType() {
- return contextHolder.get();
- }
-
- public static void clearDataSourceType() {
- contextHolder.remove();
- }
-
- /**
- * 判断指定DataSrouce当前是否存在
- *
- * @param dataSourceId
- * @return
- */
- public static boolean containsDataSource(String dataSourceId) {
- return dataSourceIds.contains(dataSourceId);
- }
- }

- 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.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
-
- @Aspect
- @Order(-1)// 保证该AOP在@Transactional之前执行
- @Component
- public class DynamicDataSourceAspect {
- private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
-
- @Before("@annotation(ds)")
- public void changeDataSource(JoinPoint point, DataSource ds) throws Throwable {
- String dsId = ds.name();
- if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
- logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature());
- } else {
- logger.debug("Use DataSource : {} > {}", ds.name(), point.getSignature());
- DynamicDataSourceContextHolder.setDataSourceType(ds.name());
- }
- }
-
- @After("@annotation(ds)")
- public void restoreDataSource(JoinPoint point, DataSource ds) {
- logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());
- DynamicDataSourceContextHolder.clearDataSourceType();
- }
- }

- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
-
-
- public class DynamicDataSource extends AbstractRoutingDataSource {
-
- @Override
- protected Object determineCurrentLookupKey() {
- return DynamicDataSourceContextHolder.getDataSourceType();
- }
-
- }
- mport java.lang.annotation.Documented;
- 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)
- @Documented
- public @interface DataSource {
- String name();
- }
# 主数据源,默认的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url= jdbc:mysql://127.0.0.1:3306/test0?useUnicode=true&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root1234
- CREATE TABLE `datasource` (
- `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
- `type` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '数据源类型',
- `driver_class_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '数据库驱动类',
- `url` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '连接url',
- `username` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '用户名',
- `password` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '密码',
- `rmark` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '备注',
- `dsname` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '数据源名称',
- `status` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '1' COMMENT '状态',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
- private void initCustomDataSources(Environment env) {
- // 读取库表中datasource获取更多数据源
- Map<String, Map<String, Object>> customInfo=getCustomDataSourceInfo();
- for (String key : customInfo.keySet()) {
- Map<String, Object> dsMap = customInfo.get(key);
- DataSource ds = buildDataSource(dsMap);
- customDataSources.put(key, ds);
- dataBinder(ds, env);
- }
- }
-
- private Map<String, Map<String, Object>> getCustomDataSourceInfo() {
- Map<String, Map<String, Object>> customMap = new HashMap<>();
- String sql = "select type,`driver_class_name`,url,username,`password`,`dsname` from datasource where status=1";
- JdbcTemplate jdbcTemplate=new JdbcTemplate(defaultDataSource);
- List<DataSourceInfo> infos=jdbcTemplate.query(sql, new RowMapper<DataSourceInfo>() {
- @Override
- public DataSourceInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
- DataSourceInfo info=new DataSourceInfo();
- info.setType(rs.getString("type"));
- info.setDriverClassName(rs.getString("driver_class_name"));
- info.setUrl(rs.getString("url"));
- info.setPassword(rs.getString("password"));
- info.setUsername(rs.getString("username"));
- info.setDsName(rs.getString("dsname"));
- return info;
- }
- });
- for(DataSourceInfo info:infos) {
- Map<String, Object> dsMap = new HashMap<>();
- dsMap.put("type", info.getType());
- dsMap.put("driver-class-name", info.getDriverClassName());
- dsMap.put("url", info.getUrl());
- dsMap.put("username", info.getUsername());
- dsMap.put("password", info.getPassword());
- customMap.put(info.getDsName(), dsMap);
- }
- return customMap;
- }

使用方式和第一种一样。
- @Aspect
- @Order(-10) // 保证该AOP在@Transactional之前执行
- @Component
- public class DynamicDataSourceAspect {
- private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
- //由于我项目中使用方法名后缀是FromDB进入AOP处理且默认第一个参数为使用数据源的key
- //这里可以自己修改想要以什么方式匹配使用数据源
- @Pointcut("execution(* com.pgl.demo.service.impl..*.*FromDB(..))")
- public void excude() {
- }
-
- @Before("excude()")
- public void changeDataSource(JoinPoint point) throws Throwable {
-
- Object obj = point.getArgs()[0];
- if(obj instanceof String) {
- String dsName=obj.toString();
- if (!DynamicDataSourceContextHolder.containsDataSource(dsName)) {
- logger.error("数据源[{}]不存在,使用默认数据源 > {}", obj, point.getSignature());
- throw new Throwable("数据源["+dsName+"]不存在");
- } else {
- logger.info("Use DataSource : {} > {}", dsName, point.getSignature());
- DynamicDataSourceContextHolder.setDataSourceType(dsName);
- }
- logger.info("-----------args DataSource : {} > {}", dsName, point.getSignature());
- }else {
- logger.error("数据源[{}]不存在", obj);
- throw new Throwable("数据源["+obj+"]不存在");
- }
-
- }
-
-
- @After("excude()")
- public void restoreDataSource(JoinPoint point) {
- Object obj = point.getArgs()[0];
- logger.info("Revert DataSource : {} > {}", obj.toString(), point.getSignature());
- DynamicDataSourceContextHolder.clearDataSourceType();
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。