精华内容
下载资源
问答
  • 数据库数据整合

    千次阅读 2019-02-28 13:39:41
    系统开发一段时间上线之后,由于功能业务复杂,数据量较大,为了监控也是运维一部分,需要对数据库数据进行检查,整合。一般会对一些关键数据进行定期检查,对于库存之类的,基本是每天都需要检查整合。每天可以...

    系统开发一段时间上线之后,由于功能业务复杂,数据量较大,为了监控也是运维一部分,需要对数据库的数据进行检查,整合。一般会对一些关键数据进行定期检查,对于库存之类的,基本是每天都需要检查整合。每天可以人工执行一些SQL,但是就会很麻烦。不够自动化。手里拿着一台电脑,竟然还要自己每天去手动。于是调查了一下想设置些东西,让sql 每天自己运行,并且把运行结果以文件形式输出。要达到的大致目标找到了,于是就开启了学习之路。下面记录一些这过程中的学习关键点。

    1:MySQL执行Select语句将结果导出到文件的方法

    看了下语句写法不复杂,于是自己写了个

    SELECT SUM(CommNum)as s from t_stock into outfile 'H://yhhsDataBack/1.sql'; ;

    运行报错:The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

    猜测是数据库安全参数设置什么的导致不能导出文件,百度这个错误,的确实是的。 也就是说,导出到什么路径,数据库已经默认了。 不能随便导出。当然也就两种方法,一种是查看默认路径是什么

    show variables like '%secure%';

    第三个参数就是允许默认的导出路径。所以改为

    SELECT SUM(CommNum)as s from t_stock into outfile 'C:\ProgramData\MySQL\MySQL Server 5.7\Uploads/1.sql'; 

    就可以正常运行。或者自己去修改MySQL的安装配置,修改这个路径参数就行。但是很麻烦,下次你换个文件,又要修改配置重启mysql .所以推荐方法2

    2:上面是运行mysql 自带的方法来实现。进一步来看,写个bat文件制定输出文件也可以实现.

    @echo off 
    cd C:/Program Files/MySQL/MySQL Server 5.7/bin
    set year=%date:~0,4%
    set month=%date:~5,2%
    set day=%date:~8,2%
    set file=%year%%month%%day%
    set filename=%year%%month%%day%.txt
    set character_set_database=GBK
    md "E:/Yhhs/StockBackups/%file%"
    mysql.exe -h localhost  -uroot -ptest123 -e"SELECT SUM(CommNum)as s from t_stock" yhhs  > E:/Yhhs/StockBackups/%file%/%filename%
    pause

    实现了按照日期时间自动创建文件。实现了输出文件的任意性。 

    cd  set  md pause 这些都是简单的cmd 命令不解释了。解释下倒数第二行参数数据库连接信息

    -h 数据库服务器地址(不是你的客户端地址)

    -u 用户名

    -p 密码

    -e 要执行的sql 语句

     yhhs 数据库名称

    > 输出的文件

    以上bat 文件写好。将bat 文件加入到系统的定时计划就行。 那天都是执行一次那个sql语句输出一个新的文件。

    在查找这个功能的时候,感觉到bat里面的命令和cmd 很想 就去百度了下bat 和cmd 的区别。 目前我的理解是,bat 和cmd 没什么区别,只是执行不同。 双击bat 文件,系统就直接运行这个bat .也是一行一行的运行里面的cmd命令。理解为cmd 要打开dos 界面实时写实时运行 ,但是bat 可以把cmd命令存起来,要用的时候,双击就好了。

    好了,再提供一个数据库备份的bat 吧,用的是mysql 自带的mysqldump.exe 这个程序。 

    @echo off 
    cd C:/Program Files/MySQL/MySQL Server 5.7/bin
    set year=%date:~0,4%
    set month=%date:~5,2%
    set day=%date:~8,2%
    set file=%year%%month%%day%
    set filename=%year%%month%%day%.sql
    set character_set_database=GBK
    md "E:/Shhs/Backups/%file%"
    mysqldump.exe --opt -Q shhs -uroot -ptest123 > E:/Shhs/Backups/%file%/%filename%
    
    

    你发现,除了mysql.exe  和mysqldump.exe之外没什么区别,只是mysqldump 没有写sql语句,select * from。。。。。 的却是的,其实你可以理解为,mysqldump已经写好了这个语句。 同样的输出就OK了。

    回来更新下。 在windos 系统下面有个很坑的东西。关于盘符。 原因是我把写的bat 由桌面放到其他E盘,点击运行,一直运行失败找不到mysql.exe  可是不是cd c:/ 这可是绝对路径哇 。 唉  cd 这个命令 的确是进去某个文件,但是只限于同一个盘符,意思是,你当前在E盘 不能直接用cd c:进C盘的文件  必须要先C:切换盘符  然后 cd ... 坑哇。  

    展开全文
  • SpringBoot整合Sharding-JDBC,实现从数据库读取sharding-jdbc数据源,实现多种数据库数据源切换,数据库方言动态切换 Hello,隔壁老王时隔很久很久又来了,今天给大家介绍的是一分库分表的框架—sharding-jdbc。...

    SpringBoot整合Sharding-JDBC,实现从数据库读取sharding-jdbc数据源,实现多种数据库数据源切换,数据库方言动态切换

    Hello,隔壁老王时隔很久很久又来了,今天给大家介绍的是一个分库分表的框架—sharding-jdbc。这个框架在我公司用到了,使用的还算比较复杂。这个项目有两种数据库,Mysql和SQLServer。因此需要动态的切换数据源,并且数据库方言也需要根据数据库类别进行切换,要不然就需要建两个一模一样的*Mapper.xml文件了。

    在网上找了很久,很多的博客介绍的都是一种数据库类别。这也就导致了,找不到Spring的动态数据源与sharding-jdbc的整合。更别说数据库方言的切换了。

    我一般不介绍概念之类的,需要看概念的,可以看这里。讲的比较深入。废话不多说了,开整吧!

    1、数据库中配置的sharing-jdbc的表结构

    CREATE TABLE `sharding_data_source` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
      `rule_name` varchar(255) DEFAULT NULL COMMENT '环境前缀',
      `database_type` varchar(255) DEFAULT NULL COMMENT '0:Mysql  1:SQLServer',
      `url` varchar(255) DEFAULT NULL COMMENT '连接地址',
      `user_name` varchar(255) DEFAULT NULL COMMENT '数据源 用户名',
      `password` varchar(255) DEFAULT NULL COMMENT '数据源密码',
      `driver_class` varchar(255) DEFAULT NULL COMMENT '驱动全类名',
      `master_slave_type` varchar(255) DEFAULT NULL COMMENT '主(master)  从(slave)',
      `sharding_column` varchar(255) DEFAULT NULL COMMENT '分库的列',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
    CREATE TABLE `sharding_data_source_detail` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
      `data_source_id` int(11) DEFAULT NULL COMMENT '数据源id',
      `logical_table` varchar(255) DEFAULT NULL COMMENT '逻辑表名',
      `sharding_column` varchar(255) DEFAULT NULL COMMENT '分表列',
      `actual_table` varchar(255) DEFAULT NULL COMMENT '物理表名',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

    其中sharding_data_source表用于存储数据库的相关信息,数据库地址、用户名、密码、数据库分片键之类的数据;sharding_data_source_detail则用于存储分表相关信息,逻辑表名、物理表名、表分片键。

    2、程序启动时从数据库中获取数据源信息并创建sharding-jdbc数据源

    先看一下sharding-jdbc与Spring动态数据源的整合

    @Configuration
    public class DynamicDataSourceConfig {
        /**
         * 将动态数据源设置为主
         *
         * @param mysqlShardingDataSource
         * @param sqlServerShardingDataSource
         * @return
         */
        @Bean
        @Primary
        @DependsOn({"mysqlShardingDataSource", "sqlServerShardingDataSource"})
        public DynamicDataSource dataSource(@Qualifier("mysqlShardingDataSource") DataSource mysqlShardingDataSource,
                                            @Qualifier("sqlServerShardingDataSource") DataSource sqlServerShardingDataSource) {
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            Map<Object, Object> targetDataSources = new HashMap<>(2);
            targetDataSources.put(DatabaseType.MYSQL_LOWER_CASE, mysqlShardingDataSource);
            targetDataSources.put(DatabaseType.SQL_SERVER_LOWER_CASE, sqlServerShardingDataSource);
            dynamicDataSource.setTargetDataSources(targetDataSources);
            dynamicDataSource.setDefaultTargetDataSource(mysqlShardingDataSource);
            return dynamicDataSource;
        }
    
        /**
         * SQLServer数据源
         *
         * @param dataSourceTemplate
         * @param restTemplate
         * @return
         * @throws SQLException
         */
        @Bean("sqlServerShardingDataSource")
        public DataSource sqlServerDataSource(DataSourceTemplate dataSourceTemplate, RestTemplate restTemplate) throws SQLException {
            return dataSourceTemplate.getDataSource(DatabaseType.SQL_SERVER, restTemplate);
        }
    
        /**
         * Mysql数据源
         *
         * @param dataSourceTemplate
         * @param restTemplate
         * @return
         * @throws SQLException
         */
        @Bean("mysqlShardingDataSource")
        public DataSource mySqlDataSource(DataSourceTemplate dataSourceTemplate, RestTemplate restTemplate) throws SQLException {
            return dataSourceTemplate.getDataSource(DatabaseType.MYSQL, restTemplate);
        }
    
        /**
         * 配置数据库方言
         *
         * @return
         */
        @Bean
        public VendorDatabaseIdProvider databaseIdProvider() {
            VendorDatabaseIdProvider provider = new VendorDatabaseIdProvider();
            Properties properties = new Properties();
            properties.setProperty(DatabaseType.MYSQL_CAPITAL, DatabaseType.MYSQL_LOWER_CASE);
            properties.setProperty(DatabaseType.SQL_SERVER_CAPITAL,  DatabaseType.SQL_SERVER_LOWER_CASE);
            provider.setProperties(properties);
            return provider;
        }
        
        /**
         * 配置Mysql的SqlSessionFactory
         *
         * @param dataSource
         * @param provider
         * @return
         * @throws Exception
         */
        @Bean("mySqlSessionFactory")
        @Primary
        @ConditionalOnBean(DynamicDataSource.class)
        public SqlSessionFactory mySqlSessionFactory(@Qualifier("mysqlShardingDataSource") DataSource dataSource, DatabaseIdProvider provider) throws Exception {
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(dataSource, provider);
            sqlSessionFactory.getConfiguration().setDatabaseId(DatabaseType.MYSQL_LOWER_CASE);
            return sqlSessionFactory;
        }
    
        /**
         * 配置SQLServer的SqlSessionFactory
         *
         * @param dataSource
         * @param provider
         * @return
         * @throws Exception
         */
        @Bean("sqlServerSessionFactory")
        @ConditionalOnBean(DynamicDataSource.class)
        public SqlSessionFactory sqlServerSessionFactory(@Qualifier("sqlServerShardingDataSource") DataSource dataSource, DatabaseIdProvider provider) throws Exception {
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(dataSource, provider);
            sqlSessionFactory.getConfiguration().setDatabaseId(DatabaseType.SQL_SERVER_LOWER_CASE);
            return sqlSessionFactory;
        }
    
        /**
         * 配置SqlSessionTemplate为自定义的SqlSessionTemplate
         *
         * @param mySqlSessionFactory
         * @param sqlServerSessionFactory
         * @return
         */
        @Bean
        @ConditionalOnBean(DynamicDataSource.class)
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mySqlSessionFactory") SqlSessionFactory mySqlSessionFactory,
                                                     @Qualifier("sqlServerSessionFactory") SqlSessionFactory sqlServerSessionFactory) {
            Map<Object, SqlSessionFactory> map = new HashMap<>(3);
            map.put(DatabaseType.MYSQL_LOWER_CASE, mySqlSessionFactory);
            map.put(DatabaseType.SQL_SERVER_LOWER_CASE, sqlServerSessionFactory);
            CustomSqlSessionTemplate sqlSessionTemplate = new CustomSqlSessionTemplate(mySqlSessionFactory);
            sqlSessionTemplate.setTargetSqlSessionFactorys(map);
            return sqlSessionTemplate;
        }
    
        private SqlSessionFactory getSqlSessionFactory(DataSource dataSource, DatabaseIdProvider provider) throws Exception {
            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setDatabaseIdProvider(provider);
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com/hyy/sharding/jdbc/mapper/*.xml"));
            return sessionFactoryBean.getObject();
        }
    
    }
    @Component
    public class DataSourceTemplate {
        /**
         * 获取指定数据库类型的数据库信息列表
         *
         * @param databaseType
         * @param restTemplate
         * @return
         * @throws SQLException
         */
        public DataSource getDataSource(String databaseType, RestTemplate restTemplate) throws SQLException {
            DataSourceHandler.setDataSourceType(DatabaseType.BASE);
            ResponseEntity<List> responseEntity = restTemplate.getForEntity("http://base-datasource-service/base/datasource/" + databaseType + "/getDataSources", List.class);
            List<DataSourceEntity> dataSources = JSON.parseArray(JSON.toJSONString(responseEntity.getBody()), DataSourceEntity.class);
            Map<String, Map<String, DataSource>> masterSlaveDataSource = new HashMap<>();
            Map<String, DataSourceDetailEntity> map = getLogicalDataSourceDetailMap(dataSources, masterSlaveDataSource);
    
            Map<String, javax.sql.DataSource> dataSourceMap = new HashMap<>();
    
            ShardingRuleConfiguration shardingRuleConfig = getShardingRuleConfiguration(map, masterSlaveDataSource, dataSourceMap);
            Properties shardingProperties = getProperties();
            return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new HashMap<>(), shardingProperties);
        }
    
    
        /**
         * 获取属性配置
         *
         * @return
         */
        private Properties getProperties() {
            Properties shardingProperties = new Properties();
            shardingProperties.put("sql.show", true);
            return shardingProperties;
        }
    
        /**
         * 获取组装好的ShardingRuleConfiguration
         *
         * @param detailMap
         * @return
         */
        private ShardingRuleConfiguration getShardingRuleConfiguration(Map<String, DataSourceDetailEntity> detailMap, Map<String,
                Map<String, javax.sql.DataSource>> masterSlaveDataSource, Map<String, javax.sql.DataSource> dataSourceMap) {
            // 分片规则配置文件类
            ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
            for (String logicTable : detailMap.keySet()) {
                DataSourceDetailEntity dataSourceDetail = detailMap.get(logicTable);
                // 表分片规则配置类
                TableRuleConfiguration ruleConfig = new TableRuleConfiguration();
    
                // 分表策略
                ComplexShardingStrategyConfiguration databaseShardingStrategyConfig = new ComplexShardingStrategyConfiguration(dataSourceDetail.getDatabaseShardingColumn(),
                        ModuloDatabaseShardingAlgorithm.class.getName());
    
                // 设置分库策略,缺省表示使用默认分库策略,即ShardingRuleConfiguration中配置的分库策略
                ruleConfig.setDatabaseShardingStrategyConfig(databaseShardingStrategyConfig);
    
                // 分表规则
                ruleConfig.setTableShardingStrategyConfig(new ComplexShardingStrategyConfiguration(dataSourceDetail.getShardingColumn(),
                        ModuloTableShardingAlgorithm.class.getName()));
    
                // 真实的数据节点
                String actualDataNodes = dataSourceDetail.getActualDataNodes();
                /*
                  1) 由数据源名 + 表名组成 以小数点分割,多个表以逗号隔开,支持inline表达式
                  2) 缺省时,以已知 数据源名称和逻辑表名称生成数据节点
                  3) 用于广播表 --即每个库中都需要一个同样的表进行关联查询,多为字典表
                  4) 只分库不分表且所有库的表结构完全一致的情况
                 */
                ruleConfig.setActualDataNodes(actualDataNodes);
                // 逻辑表名称
                ruleConfig.setLogicTable(logicTable);
                shardingRuleConfig.getTableRuleConfigs().add(ruleConfig);
            }
    
            for (String key : masterSlaveDataSource.keySet()) {
                Map<String, javax.sql.DataSource> temDatasourceMap = masterSlaveDataSource.get(key);
                MasterSlaveRuleConfiguration masterSlaveRuleConfiguration = new MasterSlaveRuleConfiguration();
                masterSlaveRuleConfiguration.setName(key);
                for (String tKey : temDatasourceMap.keySet()) {
                    if (tKey.contains("master")) {
                        masterSlaveRuleConfiguration.setMasterDataSourceName(tKey);
                    } else if (tKey.contains("slave")) {
                        masterSlaveRuleConfiguration.getSlaveDataSourceNames().add(tKey);
                    }
                    dataSourceMap.put(tKey, temDatasourceMap.get(tKey));
                }
                shardingRuleConfig.getMasterSlaveRuleConfigs().add(masterSlaveRuleConfiguration);
            }
            return shardingRuleConfig;
        }
    
        /**
         * Map<String, DataSourceDetail>  逻辑表名, 详细信息
         *
         * @param dataSources
         * @param masterSlaveDataSource
         * @return
         */
        private Map<String, DataSourceDetailEntity> getLogicalDataSourceDetailMap(List<DataSourceEntity> dataSources, Map<String, Map<String, DataSource>> masterSlaveDataSource) {
            Map<String, DataSourceDetailEntity> logicalMap = new HashMap<>();
            for (int i = 0; i < dataSources.size(); i++) {
                DataSourceEntity dataSource = dataSources.get(i);
                String dataSourceName = dataSource.getRuleName();
    
                //添加所有数据源
                if (masterSlaveDataSource.containsKey(dataSourceName)) {
                    masterSlaveDataSource.get(dataSourceName).put(dataSource.getMasterSlaveType() + i, buildDataSource(dataSource));
                } else {
                    Map<String, javax.sql.DataSource> stringDataSourceMap = new HashMap<>();
                    masterSlaveDataSource.put(dataSourceName, stringDataSourceMap);
                    stringDataSourceMap.put(dataSource.getMasterSlaveType() + i, buildDataSource(dataSource));
                }
                StringBuilder stringBuffer = new StringBuilder();
    
                for (DataSourceDetailEntity dataSourceDetail : dataSource.getDataSourceDetails()) {
    
                    String logicalTable = dataSourceDetail.getLogicalTable().toLowerCase();
                    String actualTable = dataSourceDetail.getActualTable().toLowerCase();
                    if (!logicalMap.containsKey(logicalTable)) {
                        stringBuffer.append(dataSourceName).append(".").append(actualTable);
                        dataSourceDetail.setActualDataNodes(stringBuffer.toString());
                        dataSourceDetail.setDatabaseShardingColumn(dataSource.getShardingColumn());
                        logicalMap.put(logicalTable, dataSourceDetail);
                    } else {
                        String actualDataNodes = logicalMap.get(logicalTable).getActualDataNodes();
                        stringBuffer.append(actualDataNodes).append(",").append(dataSourceName).append(".").append(actualTable);
                        logicalMap.get(logicalTable).setActualDataNodes(stringBuffer.toString());
                    }
                    stringBuffer.setLength(0);
                }
            }
            return logicalMap;
        }
    
        /**
         * 创建数据源
         *
         * @param dataSourceEntity
         * @return
         */
        private javax.sql.DataSource buildDataSource(DataSourceEntity dataSourceEntity) {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(dataSourceEntity.getDriverClass());
            dataSource.setUrl(dataSourceEntity.getUrl());
            dataSource.setUsername(dataSourceEntity.getUserName());
            dataSource.setPassword(dataSourceEntity.getPassword());
            dataSource.setMaxActive(100);
            dataSource.setInitialSize(10);
            dataSource.setTestWhileIdle(true);
            dataSource.setTestOnBorrow(false);
            dataSource.setTestOnReturn(false);
            dataSource.setMaxWait(10000);
            dataSource.setValidationQuery("select 'x'");
            dataSource.setTimeBetweenEvictionRunsMillis(60000);
            dataSource.setMinEvictableIdleTimeMillis(300000);
            dataSource.setRemoveAbandoned(true);
            dataSource.setRemoveAbandonedTimeout(80);
            return dataSource;
        }
    }

    因为需要在程序启动时就去查询数据库,但是这个时候,Spring的ApplicationContext还没有初始化,因为,没法通过注入的方式获取到*Mapper,也就没法直接通过*Mapper查询数据库了。

    在这里,给大家提供以下两种解决方案:

    (1)如果你的项目使用了Spring Cloud,那么可以通过上面的代码,调用其他服务来获取数据源信息。这种方式,就无法通过在RestTemplate上增加@LoadBalance来实现调用微服务了。因此在配置RsetTemplate时,可以使用如下方式:

    @Bean
    public RestTemplate restTemplate(final List<RestTemplateCustomizer> customizers) {
        RestTemplate restTemplate = new RestTemplate();
        for (RestTemplateCustomizer customizer : customizers) {
            customizer.customize(restTemplate);
        }
        return restTemplate;
    }

    (2)如果你的项目没有使用到Spring Cloud,那么就只能通过硬编码的方式来获取数据源信息了。具体配置方式如下:

    @Component
    public class DataSourceTemplate {
        public static ConcurrentHashMap<String, List<DataSourceEntity>> concurrentHashMap = new ConcurrentHashMap<>();
    
        public DataSourceTemplate() {
            Connection connection = null;
            try {
                String driverClassName = "com.mysql.jdbc.Driver";
                String url = "xxxx";
                String username = "xxxx";
                String password = "xxxx";
                Class.forName(driverClassName);
                connection = DriverManager.getConnection(url, username, password);
                PreparedStatement preparedStatement = connection.prepareStatement("select * from sharding_data_source");
                ResultSet resultSet = preparedStatement.executeQuery();
                DataSourceEntity dataSource;
                List<DataSourceDetailEntity> dataSourceDetails;
                DataSourceDetailEntity dataSourceDetail;
                while (resultSet.next()) {
                    dataSource = new DataSourceEntity();
                    dataSource.setId(resultSet.getLong("id"));
                    dataSource.setRuleName(resultSet.getString("rule_name"));
                    dataSource.setDatabaseType(resultSet.getString("database_type"));
                    dataSource.setUrl(resultSet.getString("url"));
                    dataSource.setUserName(resultSet.getString("user_name"));
                    dataSource.setPassword(resultSet.getString("password"));
                    dataSource.setDriverClass(resultSet.getString("driver_class"));
                    dataSource.setMasterSlaveType(resultSet.getString("master_slave_type"));
                    dataSource.setShardingColumn(resultSet.getString("sharding_column"));
                    preparedStatement = connection.prepareStatement("select * from sharding_data_source_detail where data_source_id = " + dataSource.getId());
                    ResultSet resultSet1 = preparedStatement.executeQuery();
                    dataSourceDetails = new ArrayList<>();
                    while (resultSet1.next()) {
                        dataSourceDetail = new DataSourceDetail();
                        dataSourceDetail.setLogicalTable(resultSet1.getString("logical_table"));
                        dataSourceDetail.setShardingColumn(resultSet1.getString("sharding_column"));
                        dataSourceDetail.setActualTable(resultSet1.getString("actual_table"));
                        dataSourceDetails.add(dataSourceDetail);
                    }
                    dataSource.setDataSourceDetails(dataSourceDetails);
                    concurrentHashMap.computeIfAbsent(dataSource.getDatabaseType(), k -> new ArrayList<>());
                    concurrentHashMap.get(dataSource.getDatabaseType()).add(dataSource);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public DataSource getDataSource(String databaseType) throws SQLException {
    	    DataSourceHandler.setDataSourceType(DatabaseType.BASE);
    	    List<DataSourceEntity> dataSources = concurrentHashMap.get(databaseType);
    
    	    Map<String, Map<String, DataSource>> masterSlaveDataSource = new HashMap<>();
    	    Map<String, DataSourceDetailEntity> map = getLogicalDataSourceDetailMap(dataSources, masterSlaveDataSource);
    
    	    Map<String, DataSource> dataSourceMap = new HashMap<>();
    
    	    ShardingRuleConfiguration shardingRuleConfig = getShardingRuleConfiguration(map, masterSlaveDataSource, dataSourceMap);
    	    Properties shardingProperties = getProperties();
    	    return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new HashMap<>(), shardingProperties);
    	}
    }

    其余代码与上面的一样,只是在实例化DataSourceTemplate类时,以硬编码的方式查询数据库,并将数据库信息放到ConcurrentHashMap中。后续需要某类型的数据库信息时,直接从ConcurrentHashMap中取就可以了。

    到了这里,基本上可以实现数据源动态切换了。注意,只是可以切换数据源了。统统的Mapper文件,你还得写多份,以区分不同的数据库。如果在网上搜,你会发现让你配置VendorDatabaseIdProvider。在上面的配置,你会发现我们已经配置了,但是还是不起作用。那是因为网上的教程都是基于java.sql.DataSource的,因此只配置VendorDatabaseIdProvider是可以做到数据库方言根据数据源类型切换。但是,我们现在用的是Sharding-Jdbc的数据源,所以哪怕配置了VendorDatabaseIdProvider,也没法做到数据库方言的自动切换。我们还需要实现SqlSessionTemplate接口,重写getSqlSessionFactory方法。主要是为了根据线程中设置的数据类型返回对应的SqlSessionFactory。

    public class CustomSqlSessionTemplate extends SqlSessionTemplate {
        private final SqlSessionFactory sqlSessionFactory;
        private final ExecutorType executorType;
        private final SqlSession sqlSessionProxy;
        private final PersistenceExceptionTranslator exceptionTranslator;
    
        private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
        private SqlSessionFactory defaultTargetSqlSessionFactory;
    
        public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {
            this.targetSqlSessionFactorys = targetSqlSessionFactorys;
        }
    
        public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {
            this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
        }
    
        public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
            this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
        }
    
        private CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
            this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration()
                    .getEnvironment().getDataSource(), true));
        }
    
        private CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
                                         PersistenceExceptionTranslator exceptionTranslator) {
    
            super(sqlSessionFactory, executorType, exceptionTranslator);
    
            this.sqlSessionFactory = sqlSessionFactory;
            this.executorType = executorType;
            this.exceptionTranslator = exceptionTranslator;
    
            this.sqlSessionProxy = (SqlSession) newProxyInstance(
                    SqlSessionFactory.class.getClassLoader(),
                    new Class[] { SqlSession.class },
                    new SqlSessionInterceptor());
    
            this.defaultTargetSqlSessionFactory = sqlSessionFactory;
        }
    
        @Override
        public SqlSessionFactory getSqlSessionFactory() {
    
            SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(DataSourceHandler.getDataSourceType());
            if (targetSqlSessionFactory != null) {
                return targetSqlSessionFactory;
            } else if (defaultTargetSqlSessionFactory != null) {
                return defaultTargetSqlSessionFactory;
            } else {
                Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
                Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
            }
            return this.sqlSessionFactory;
        }
    
        @Override
        public Configuration getConfiguration() {
            return this.getSqlSessionFactory().getConfiguration();
        }
    
        @Override
        public ExecutorType getExecutorType() {
            return this.executorType;
        }
    
        @Override
        public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
            return this.exceptionTranslator;
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <T> T selectOne(String statement) {
            return this.sqlSessionProxy.<T> selectOne(statement);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <T> T selectOne(String statement, Object parameter) {
            return this.sqlSessionProxy.<T> selectOne(statement, parameter);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
            return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
            return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
            return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <E> List<E> selectList(String statement) {
            return this.sqlSessionProxy.<E> selectList(statement);
        }
    
        /**
         * {@inheritDoc}
         */
    
        @Override
        public <E> List<E> selectList(String statement, Object parameter) {
            return this.sqlSessionProxy.<E> selectList(statement, parameter);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
            return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void select(String statement, ResultHandler handler) {
            this.sqlSessionProxy.select(statement, handler);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void select(String statement, Object parameter, ResultHandler handler) {
            this.sqlSessionProxy.select(statement, parameter, handler);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
            this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public int insert(String statement) {
            return this.sqlSessionProxy.insert(statement);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public int insert(String statement, Object parameter) {
            return this.sqlSessionProxy.insert(statement, parameter);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public int update(String statement) {
            return this.sqlSessionProxy.update(statement);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public int update(String statement, Object parameter) {
            return this.sqlSessionProxy.update(statement, parameter);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public int delete(String statement) {
            return this.sqlSessionProxy.delete(statement);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public int delete(String statement, Object parameter) {
            return this.sqlSessionProxy.delete(statement, parameter);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public <T> T getMapper(Class<T> type) {
            return getConfiguration().getMapper(type, this);
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void commit() {
            throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void commit(boolean force) {
            throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void rollback() {
            throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void rollback(boolean force) {
            throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void close() {
            throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void clearCache() {
            this.sqlSessionProxy.clearCache();
        }
    
        /**
         * {@inheritDoc}
         */
        @Override
        public Connection getConnection() {
            return this.sqlSessionProxy.getConnection();
        }
    
        /**
         * {@inheritDoc}
         * @since 1.0.2
         */
        @Override
        public List<BatchResult> flushStatements() {
            return this.sqlSessionProxy.flushStatements();
        }
    
        /**
         * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also
         * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to
         * the {@code PersistenceExceptionTranslator}.
         */
        private class SqlSessionInterceptor implements InvocationHandler {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                final SqlSession sqlSession = getSqlSession(
                        CustomSqlSessionTemplate.this.getSqlSessionFactory(),
                        CustomSqlSessionTemplate.this.executorType,
                        CustomSqlSessionTemplate.this.exceptionTranslator);
                try {
                    Object result = method.invoke(sqlSession, args);
                    if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory())) {
                        // force commit even on non-dirty sessions because some databases require
                        // a commit/rollback before calling close()
                        sqlSession.commit(true);
                    }
                    return result;
                } catch (Throwable t) {
                    Throwable unwrapped = unwrapThrowable(t);
                    if (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                        Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator
                                .translateExceptionIfPossible((PersistenceException) unwrapped);
                        if (translated != null) {
                            unwrapped = translated;
                        }
                    }
                    throw unwrapped;
                } finally {
                    closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory());
                }
            }
        }
    }

    配置好后,我们的*Mapper.xml就只需要一份,相同的业务功能,指定对应的databaseId即可。

    <mapper namespace="com.hyy.sharding.jdbc.mapper.CodeMapper">
        <select id="getCodes" resultType="java.lang.String" databaseId="mysql">
            SELECT CODE FROM coupon_seed LIMIT 10
        </select>
    
        <select id="getCodes" resultType="java.lang.String" databaseId="sqlServer">
            SELECT TOP 10 CODE FROM coupon_seed
        </select>
    </mapper>

    项目启动后,调用分别调用http://localhost:8082/code/mysql/getCodeshttp://localhost:8082/code/sqlServer/getCodes,查看控制台输出:

    demo看这里

     

    展开全文
  • springboot连接多个数据库

    万次阅读 热门讨论 2018-08-22 17:13:15
    今天借到一个新的需求,需要把...这里把连接一个数据库的情况也记录一下,好做对比 一、连接一个数据库 1.启动类 @SpringBootApplication //扫描mapper映射类所在路径 @MapperScan(basePackages = "com.xh....

    今天借到一个新的需求,需要把自己数据库某个表的数据迁移到别的数据库中,于是百度,中间出现了一些细节的问题,解决花了点时间,在此记录一下,下次避免出现过的错误

    这里把连接一个数据库的情况也记录一下,好做对比

    一、连接一个数据库

    1.启动类

    @SpringBootApplication
    //扫描mapper映射类所在路径
    @MapperScan(basePackages = "com.xh.iot.repositories.mapper")
    public class EmDataProcApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EmDataProcApplication.class, args);
        }
    }

    2.配置文件application.properties

    # MySql Database
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/iothub_base?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
    spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=Xtjc0551Mysql!
    
    
    # MyBaits,xml映射文件所在目录,resources下
    mybatis.mapper-locations=classpath:mapping/*.xml

    3.添加mapper对应的service和serviceImpl,最后在controller中添加service实例操作数据库

    二、连接多个数据库

    1.启动类

    //EnableAutoConfiguration注解,关闭springBoot关于mybatis的一些自动注入
    @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class, MybatisAutoConfiguration.class})
    //加入定时器
    @EnableScheduling
    @SpringBootApplication
    public class DataTransGsiotApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DataTransGsiotApplication.class, args);
        }
    }

    2.配置文件application.properties,配置了2个库的连接

    #  MySql Database
    #org_base库
    spring.datasource.org.jdbcUrl=jdbc:mysql://127.0.0.1:3306/org_base?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
    spring.datasource.org.driverClassName = com.mysql.cj.jdbc.Driver
    spring.datasource.org.username=root
    spring.datasource.org.password=Xtjc0551Mysql!
    #gs_iot_v1库
    spring.datasource.gsiot.jdbcUrl=jdbc:mysql://127.0.0.1:3306/gs_iot_v1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
    spring.datasource.gsiot.driverClassName = com.mysql.cj.jdbc.Driver
    spring.datasource.gsiot.username=root
    spring.datasource.gsiot.password=root

    3.创建2个数据库连接的配置类

    GsIotDataSourceConfig类

    package com.xh.iot.repositories.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    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.xh.iot.repositories.mapper.gsiot",sqlSessionFactoryRef = "gsiotSqlSessionFactory")
    public class GsIotDataSourceConfig {
        @Primary
        @Bean(name = "gsiotDataSource")
        @ConfigurationProperties("spring.datasource.gsiot")
        public DataSource masterDataSource(){
            return DataSourceBuilder.create().build();
        }
    
        @Bean(name = "gsiotSqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("gsiotDataSource") DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources("classpath:mapping/gsiot/*.xml"));
            return sessionFactoryBean.getObject();
        }
    }

     OrgDataSourceConfig类

    package com.xh.iot.repositories.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    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.xh.iot.repositories.mapper.org",sqlSessionFactoryRef = "orgSqlSessionFactory")
    public class OrgDataSourceConfig {
        @Primary
        @Bean(name = "orgDataSource")
        @ConfigurationProperties("spring.datasource.org")
        public DataSource masterDataSource(){
            return DataSourceBuilder.create().build();
        }
    
        @Bean(name = "orgSqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("orgDataSource") DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources("classpath:mapping/org/*.xml"));
            return sessionFactoryBean.getObject();
        }
    }

    注意:

    1、注意多个数据库的application.properties文件,数据库连接用jdbcUrl或者jdbc-url

    2、如果有更多的数据库连接,可以按照这种方式添加;不同的数据库,需要不同的配置类,可以把这些配置类放在同一个目录中
    3、 每个配资类中,需要指明当前数据库表的xml文件和mapper映射文件所在的包名,并且把xml和mapper放置到对应的目录中
    4、其他的比如:xml里面sql语句的写法和正常一个连接是一模一样,添加mapper对应的service和serviceImpl,最后在controller中添加不同的service实例就可以操作对应数据库了

    展开全文
  • SpringBoot2.0.4配置多个数据库

    万次阅读 2018-11-16 12:28:59
    使用场景: 一个服务需要根据不同的业务逻辑对不同的数据库进行...两个数据库的DataSource实例,代码中用来处理两个数据库连接的部分。 两个数据库中的表分别对应的JavaBean。 操作(DML)两个数据库表的Reposi...

    使用场景: 一个Spring Boot服务根据不同的业务逻辑需要对不同的数据库进行操作。

    一、举例说明

    假设需要处理的两个数据库是test1、test2,那么必须要有的是:

    1. 两个数据库的配置参数(写在配置文件application.properties)。
    2. 两个数据库的DataSource实例,代码中用来处理两个数据库连接的代码。
    3. 两个数据库表对应的相应的JavaBean
    4. 操作(DML)两个数据库的Repository
    5. 将以上提到的配置、实例等整合到一起,分别对不同数据库进行事务管理配置,也必须有两部分。

    二、代码逻辑

    上面提到的必要条件都是“两个”,那么就必须要有区分,这样才能保证操作一个数据库表时不会影响到另外一个数据库中的表。下面整理一下Spring boot是如何对每部分进行区分的。

    1. 配置文件中数据库参数是利用前缀来区分不同的配置。
    2. DataSource实例是利用前缀去创建相应的实例,并且为每个DataSource使用不同的beanName。
    3. 不同数据库表对应的JavaBean是通过包名来划分的。(也可以通过类名划分)。
    4. Repository也是通过包名划分的。(也可以通过类名划分)
    5. 通过装配相对应的bean、包名、配置来实现相对应的整合。

    三、代码逻辑

    继续上面提的test1、test2数据库,假设test1中只有一个user1表,test2中只有一个user2表,完成多数据源的代码实现。

    第1步: application.properties配置文件入下:

    #test1数据库的配置
    test1.spring.datasource.jdbcUrl = jdbc:mysql://192.168.1.105:3306/test1?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8
    test1.spring.datasource.username = mysql
    test1.spring.datasource.password = mysql
    test1.spring.datasource.driverClassName = com.mysql.jdbc.Driver
    
    #test2数据库的配置
    test2.spring.datasource.jdbcUrl = jdbc:mysql://192.168.1.105:3306/test2?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8
    test2.spring.datasource.username = mysql
    test2.spring.datasource.password = mysql
    test2.spring.datasource.driverClassName = com.mysql.jdbc.Driver
    

    配置文件中要注意:

    • jdbcUrl可以写成jdbc-url,不能写成jdbc.urlurl
    • driverClassName可以写成driver-class-name,不能写成driver.class.name

    第2步: DataSource实例的创建,这个实例需要写在一个类里面,实例创建时,要用到配置文件中的不同数据参数的前缀,创建相应的实例。

    DataSourceConfig代码如下:

    
    package com.xyh.test.config;
    
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    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 javax.sql.DataSource;
    
    @Configuration
    public class DataSourceConfig {
    
        /**
         * 创建test1的DataSource实例
         * @return
         */
        @Primary //配置一个主连接
        @Bean(name = "test1DataSource")
        @Qualifier("test1DataSource")
        @ConfigurationProperties(prefix="test1.spring.datasource")
        public DataSource test1DataSource() {
            return DataSourceBuilder.create().build();
        }
    
        /**
         * 创建test2的DataSource实例
         * @return
         */
        @Bean(name = "test2DataSource")
        @Qualifier("test2DataSource")
        @ConfigurationProperties(prefix="test2.spring.datasource")
        public DataSource test2aryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
    }
    
    

    第3步: 创建数据库表对应的JavaBean,test1和test2数据库中的表分别放在相应名称的包下。
    在这里插入图片描述

    User1代码如下:

    package com.xyh.test.entity.test1;
    
    import org.hibernate.annotations.GenericGenerator;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    
    @Entity
    public class User1 {
    
        @Id
        @Column(length = 32, nullable = true)
        @GenericGenerator(name = "sys_uuid", strategy = "uuid")
        @GeneratedValue(generator = "sys_uuid")
        private String id;
        private String name;
    
    	//……省略get/set方法
    }
    

    User2代码如下:

    package com.xyh.test.entity.test1;
    
    import org.hibernate.annotations.GenericGenerator;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    
    @Entity
    public class User1 {
    
        @Id
        @Column(length = 32, nullable = true)
        @GenericGenerator(name = "sys_uuid", strategy = "uuid")
        @GeneratedValue(generator = "sys_uuid")
        private String id;
        private String name;
    
    	//……省略get/set方法
    }
    

    第4步: 创建操作对应数据库的Repository,与JavaBean的分包方式一致。

    在这里插入图片描述

    User1Repository的代码如下:

    package com.xyh.test.repository.test1;
    
    import com.xyh.test.entity.test1.User1;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface User1Repository extends JpaRepository<User1,String> {
    }
    
    
    

    User2Repository的代码如下:

    package com.xyh.test.repository.test2;
    
    import com.xyh.test.entity.test2.User2;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface User2Repository extends JpaRepository<User2,String> {
        
    }
    

    第5步: 整合配置和Bean、配置事务的配置类,test1对应的类是Test1DataSourceConfig,test2对应的类是Test2DataSourceConfig,前面几步对JavaBean和repository进行分包,都是在这个类中进行配置区分的。

    Test1DataSourceConfig代码如下:

    package com.xyh.test.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
    import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
    import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.persistence.EntityManager;
    import javax.sql.DataSource;
    import java.util.Map;
    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
            entityManagerFactoryRef = "entityManagerFactoryTest1",
            transactionManagerRef = "transactionManagerTest1",
            basePackages = {"com.xyh.test.repository.test1"})//设置repository所在位置
    public class Test1DataSourceConfig {
    
    
        @Autowired(required=false)//required=true表示bean必须存在,否则注入失败,默认为true
        @Qualifier("test1DataSource")
        private DataSource test1DataSource;
        
    
        @Primary
        @Bean(name = "entityManagerTest1")
        public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
            return entityManagerFactoryTest1(builder).getObject().createEntityManager();
        }
    
    
        @Autowired
        private JpaProperties jpaProperties;
    
    
        private Map<String, Object> getVendorProperties() {
            return jpaProperties.getHibernateProperties(new HibernateSettings());
        }
    
        @Primary
        @Bean(name = "entityManagerFactoryTest1")
        public LocalContainerEntityManagerFactoryBean entityManagerFactoryTest1(EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(test1DataSource)
                    .packages("com.xyh.test.entity.test1")//设置实体类所在位置
                    .persistenceUnit("test1PersistenceUnit")
                    .properties(getVendorProperties())
                    .build();
        }
    
        @Primary
        @Bean(name = "transactionManagerTest1")
        PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
            return new JpaTransactionManager(entityManagerFactoryTest1(builder).getObject());
        }
        
    }
    

    Test2DataSourceConfig代码如下:

    package com.xyh.test.config;
    
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
    import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
    import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.annotation.Resource;
    import javax.persistence.EntityManager;
    import javax.sql.DataSource;
    import java.util.Map;
    
    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
            entityManagerFactoryRef = "entityManagerFactoryTest2",
            transactionManagerRef = "transactionManagerTest2",
            basePackages = {"com.xyh.test.repository.test2"}) //repository类的包
    public class Test2DataSourceConfig {
    
        @Resource
        @Qualifier("test2DataSource")
        private DataSource test2DataSource;
    
    
        @Bean(name = "entityManagerTest2")
        public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
            return entityManagerFactoryTest2(builder).getObject().createEntityManager();
        }
    
        @Resource
        private JpaProperties jpaProperties;
    
        private Map<String, Object> getVendorProperties() {
            return jpaProperties.getHibernateProperties(new HibernateSettings());
        }
    
        /**
         * 设置实体类所在位置
         */
        @Bean(name = "entityManagerFactoryTest2")
        public LocalContainerEntityManagerFactoryBean entityManagerFactoryTest2(EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(test2DataSource)
                    .packages("com.xyh.test.entity.test2")//javabean的包
                    .persistenceUnit("test2PersistenceUnit")
                    .properties(getVendorProperties())
                    .build();
        }
    
        @Bean(name = "transactionManagerTest2")
        public PlatformTransactionManager transactionManagerTest2(EntityManagerFactoryBuilder builder) {
            return new JpaTransactionManager(entityManagerFactoryTest2(builder).getObject());
        }
    
    }
    
    

    四、测试

    写一个controller,然后分别注入不同的Repository,调用相应save方法,可以看到相应的数据库表增加了一条记录。

    @RestController
    @EnableConfigurationProperties
    public class IndexController {
    
        @Autowired
        private User1Repository user1Repository;
    
        @Autowired
        private User2Repository user2Repository;
    
        @RequestMapping("/")
        public String index(){
    
            User1 user1 = new User1();
            user1.setName("user1Name");
            user1Repository.save(user1);
    
            User2 user2 = new User2();
            user2.setName("user2Name");
    
            user2Repository.save(user2);
            return "hello world";
        }
    }
    
    展开全文
  • SQL Server多个数据库合并

    千次阅读 2019-05-13 11:26:27
    1、创建两个数据库A_TEST,B_TEST。 2、将数据库A合并到数据库B。选中数据库,右键——任务——导出数据。 3、转到导出向导,选择下一步。 4、输入服务器名称,选择身份验证(默认Windows),选择导出的...
  • 这边文章的多数据源写法参照了 http://www.ityouknow.com/springboot/2016/11/25/spring-boot-multi-mybatis.html 1、pom.xml配置 <!-- mybatis --> <dependency> <groupId>org.mybatis....
  • 随着SAAS平台越来越盛行,很情况下,希望应用程序搭建一套,为每用户建立一私有的数据库,所有程序使用一套. 开动吧: 一、 首先继承AbstractRoutingDataSource,从名称上看为抽象路由数据源,就是spring为提供...
  • 声明,使用JDK8、idea、lombok、springboot2.0进行测试: 》 》 1、mybatis多数据源的使用场景: 操作同一台服务器上不同的数据库,或者地机器上的相同或...数据隔离,把数据分别存放在test、test02这两个数据库...
  • Mybatis多个数据库连接配置

    千次阅读 2019-02-28 18:36:21
    Mybatis多个数据库连接配置 1 数据库的连接信息 app.properties配置文件中的两个数据库的连接信息 2 mybatis配置文件读取app.properties中的连接信息 &amp;lt;?xml version=&quot;1.0&quot; ...
  • 在ssm项目中,能通过配置连接两个或多个数据库吗,比如在mysql中有数据库A和数据库B 我想同时对两个数据库建立链接。能用select * from A.tableName,B.tableName查询到不同 数据库中的两个表的数据
  • Mysql数据库切分及整合方案

    千次阅读 2016-06-30 16:17:07
    我们已经很清楚通过数据库的数据切分可以极大的...这一节我们主要针对的内容就是分析可以使用的各种可以帮助我们实现数据切分以及数据整合的整体解决方案。 数据的整合很难依靠数据库本身来达到这效果,虽然MyS
  • 以前写过一篇教程,Springboot AOP...网上大多流传的springboot系列的切换多数据源都是以上那种写死在配置文件里的方式,这样如果我需要切换的数据源有10,那么这种方式会不会显得稍微有点繁琐了。 现在这篇介绍...
  • 由于微服务分库导致无法跨库(忽略 db_name.table_name 方式)统计查询,因此利用 MySQL 主从复制的方式,将主服务器上的多个数据库同步到从服务器上的单个数据库上,从库设置只读,仅用于统计查询。 假设主服务器上...
  • SequoiaDB巨杉数据库也成为了Spark官方认证的全球合作伙伴和授权的Spark提供商之一,SequoiaDB巨杉数据库也是国内唯一获得该认证和发行权的数据库公司。 深度整合Spark 2.0 SequoiaDB 2.0通过深度集成最新的...
  • spring mvc mybatis连接多个数据库
  • 上一篇博客说到同一问题,...第一步:将spring和mybatis整合,这过程就不具体演示了,在这过程中创建了直接使用的五配置文件、两类、一标识。 五配置文件: jdbc.propertis(数据库连接信息) app...
  • 数据库, 数据仓库, 数据集市,数据湖,数据中台

    千次阅读 多人点赞 2019-02-22 16:21:47
    转载声明 本文大量内容系转载自以下文章,有删改,并参考其他文档资料加入了一些内容: 数据仓库和数据集市的区别 ...本文简要介绍数据库 数据仓库和数据集市概念,并做简要对比。 0x01 数据仓库和数据库 1.1 数...
  • 之前在解决一项目连接数据库问题的时候在网上苦寻答案无果,于是显示自己研究,终于黄天不负有心,接先来我...第一步:将spring和mybatis整合,这过程就不具体演示了,在这过程中创建了直接使用的五配置文件。
  • springboot整合多数据

    千次阅读 2018-12-29 19:47:04
    今天演示一下使用springboot整合多个数据源在一个工程中,个人比较习惯于使用xml方式写sql语句,因此这里演示使用xml形式的整合方式,方便大家作参考; 1、首先在mysql创建两个不同的库,分别是:babytun 和...
  • mysql 数据库拆分与整合方案

    千次阅读 2015-05-18 11:03:39
    文章整理自:...所谓数据库的切分,就是我们按照某些特定的条件,将一台数据库上的数据分散到数据库服务器上。因为使用台服务器,所以当一台服务器宕机后,整个系统只有部分数据不可用,而
  • springboot-mybatis多数据源的两种整合方法

    万次阅读 多人点赞 2018-07-17 18:23:15
    springboot-mybatis整合多...一个项目使用多个数据库(无论是主从复制- - 读写分离还是分布式数据库结构)的重要性变得越来越明显。传统项目中(个人对传统项目的理解就是所有的业务模块都在一个tomcat中完成,多个相
  • Yandex开源的数据分析的数据库,名字叫做ClickHouse,适合流式或批次入库的时序数据。ClickHouse不应该被用作通用数据库,而是作为超高性能的海量数据快速查询的分布式实时处理平台,在数据汇总查询方面(如GROUP BY)...
  • MySQL 两个数据库表中合并数据

    千次阅读 2019-10-03 21:51:41
    个数据库表中合并数据 如果有 t1 和 t2 两个数据库表格,它们两个对应的字段是相同的。如何将 t2 的数据插入到t1中去呢? insert into t1 select * from t2 INSERT INTO domestic_auction_artron_2018_...
  • Springboot整合Mybatis多数据源配置

    万次阅读 热门讨论 2019-06-09 14:06:44
    话不说,直接进入正题。源码地址:https://github.com/AliceAsuna/KiritoV1.git 目录 一、数据库配置文件 二、配置类 主数据源配置类: 次数据源配置类: 三、项目结构(重点是mapper结构和配置类里的路径...
  • 本篇文章主要是完成springboot整合多数据源,一般都用来解决那些比较复杂需要连接不同的数据库来支持业务,可以做到不同的接口连接不同的数据库来请求数据,在配置方面不同于其他人的文章在application.yml文件里面...
  • 数据库数据仓库、数据集市的区别与联系

    万次阅读 多人点赞 2018-09-06 19:24:33
    一些刚进公司的同学有时候会问我,我们的数据库信息为什么有冗余呢,这表的设计和之前学校学习的不一样呢,为什么不符合三范式呢等等。下面我会依次介绍下数据库数据仓库、数据集市的概念以及他们之间的区别。 ...
  • 现有数据整合方案介绍

    千次阅读 2009-10-20 21:23:00
    数据整合方案是数据整合的研究重点,目前实际应用中已经形成了一些较为成熟的案例,主要有基于数据仓库的整合方案、基于中间件的整合方案、基于Web Services的整合方案、基于虚拟数据库的整合方案。随着数据整合技术...
  • springboot+springsecurity+oauth2整合(并用mysql实现持久化) 本文主要讲的是,实现oauth2的工作流程,需要对oauth2.0概念有一定的基础知识了解。阅读前请学习oauth2.0的理论知识。文末有此项目代码地址。 ...
  • springboot整合mybatis:第一步配置数据源 在application.properties文件中配置数据源,如下配置:spring.datasource.jdbcUrl=jdbc:oracle:thin:@10.21.16.140:1521:ora11g spring.datasource.username=brmuser ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 204,489
精华内容 81,795
关键字:

多个数据库数据整合