Commit a408909a by fengshuonan

更新数据源配置方式

parent 686750b8
...@@ -16,7 +16,7 @@ USE guns; ...@@ -16,7 +16,7 @@ USE guns;
Target Server Version : 50724 Target Server Version : 50724
File Encoding : 65001 File Encoding : 65001
Date: 11/06/2019 14:01:41 Date: 12/06/2019 17:17:50
*/ */
SET NAMES utf8mb4; SET NAMES utf8mb4;
...@@ -28,11 +28,12 @@ SET FOREIGN_KEY_CHECKS = 0; ...@@ -28,11 +28,12 @@ SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `database_info`; DROP TABLE IF EXISTS `database_info`;
CREATE TABLE `database_info` ( CREATE TABLE `database_info` (
`db_id` bigint(20) NOT NULL COMMENT '主键id', `db_id` bigint(20) NOT NULL COMMENT '主键id',
`db_name` varchar(255) NOT NULL COMMENT '数据库名称', `db_name` varchar(255) NOT NULL COMMENT '数据库名称(英文名称)',
`jdbc_driver` varchar(255) NOT NULL COMMENT 'jdbc的驱动类型', `jdbc_driver` varchar(255) NOT NULL COMMENT 'jdbc的驱动类型',
`user_name` varchar(255) NOT NULL COMMENT '数据库连接的账号', `user_name` varchar(255) NOT NULL COMMENT '数据库连接的账号',
`password` varchar(255) NOT NULL COMMENT '数据库连接密码', `password` varchar(255) NOT NULL COMMENT '数据库连接密码',
`jdbc_url` varchar(2000) NOT NULL COMMENT 'jdbc的url', `jdbc_url` varchar(2000) NOT NULL COMMENT 'jdbc的url',
`remarks` varchar(255) DEFAULT NULL COMMENT '备注,摘要',
`create_time` datetime DEFAULT NULL COMMENT '创建时间', `create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`db_id`) USING BTREE PRIMARY KEY (`db_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='数据库信息表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='数据库信息表';
...@@ -41,7 +42,7 @@ CREATE TABLE `database_info` ( ...@@ -41,7 +42,7 @@ CREATE TABLE `database_info` (
-- Records of database_info -- Records of database_info
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `database_info` VALUES (1, '默认数据库', 'com.mysql.jdbc.Driver', 'root', 'root', 'jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT', '2019-05-11 13:51:19'); INSERT INTO `database_info` VALUES (1, 'master', 'com.mysql.jdbc.Driver', 'root', 'root', 'jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT', 'Guns启动的数据源', '2019-05-11 13:51:19');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-vip</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>guns-base-db-container</artifactId>
<packaging>jar</packaging>
<dependencies>
<!--基础组件-->
<dependency>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-base</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
package cn.stylefeng.datasource.container.context;
import cn.stylefeng.datasource.container.dao.DataBaseInfoDao;
import cn.stylefeng.roses.core.config.properties.DruidProperties;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import javax.sql.DataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 数据源的上下文容器(单例)
*
* @author fengshuonan
* @date 2019-06-12-13:37
*/
public class DataSourceContext {
/**
* 主数据源名称
*/
public static final String MASTER_DATASOURCE_NAME = "master";
/**
* 数据源容器
*/
private static Map<String, DataSource> DATA_SOURCES = new ConcurrentHashMap<>();
/**
* 初始化所有dataSource
*
* @author fengshuonan
* @Date 2019-06-12 13:48
*/
public static void initDataSource(DruidProperties masterDataSourceProperties) {
//从数据库中获取所有的数据源信息
DataBaseInfoDao dataBaseInfoDao = new DataBaseInfoDao(masterDataSourceProperties);
Map<String, DruidProperties> allDataBaseInfo = dataBaseInfoDao.getAllDataBaseInfo();
//根据数据源信息初始化所有的DataSource
for (Map.Entry<String, DruidProperties> entry : allDataBaseInfo.entrySet()) {
String dbName = entry.getKey();
DruidProperties druidProperties = entry.getValue();
//通过property创建DataSource
DataSource dataSource = createDataSource(dbName, druidProperties);
DATA_SOURCES.put(dbName, dataSource);
}
}
/**
* 新增datasource
*
* @author fengshuonan
* @Date 2019-06-12 14:51
*/
public void addDataSource(String dbName, DataSource dataSource) {
DATA_SOURCES.put(dbName, dataSource);
}
/**
* 获取数据源
*
* @author fengshuonan
* @Date 2019-06-12 13:50
*/
public static Map<String, DataSource> getDataSources() {
return DATA_SOURCES;
}
/**
* 数据源创建模板
*/
private static DataSource createDataSource(String dataSourceName, DruidProperties druidProperties) {
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
atomikosDataSourceBean.setUniqueResourceName(dataSourceName);
atomikosDataSourceBean.setMaxPoolSize(20);
atomikosDataSourceBean.setBorrowConnectionTimeout(60);
atomikosDataSourceBean.setXaProperties(druidProperties.createProperties());
return atomikosDataSourceBean;
}
}
package cn.stylefeng.datasource.container.context;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* mybatis的sqlSessionFactory的上下文容器(单例)
*
* @author fengshuonan
* @date 2019-06-12-13:37
*/
public class SqlSessionFactoryContext {
private static Map<Object, SqlSessionFactory> sqlSessionFactories = new ConcurrentHashMap<>();
/**
* 添加sqlSessionFactory
*
* @author fengshuonan
* @Date 2019-06-12 15:28
*/
public static void addSqlSessionFactory(String name, SqlSessionFactory sqlSessionFactory) {
sqlSessionFactories.put(name, sqlSessionFactory);
}
/**
* 获取所有的sqlSessionFactory
*
* @author fengshuonan
* @Date 2019-06-12 13:49
*/
public static Map<Object, SqlSessionFactory> getSqlSessionFactorys() {
return sqlSessionFactories;
}
}
package cn.stylefeng.datasource.container.dao;
import cn.stylefeng.datasource.container.exception.DataSourceInitException;
import cn.stylefeng.roses.core.config.properties.DruidProperties;
import lombok.extern.slf4j.Slf4j;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
/**
* 操作数据源信息的dao
*
* @author fengshuonan
* @date 2019-06-12-14:02
*/
@Slf4j
public class DataBaseInfoDao {
private String MYSQL_SQL_LIST = "select db_name,jdbc_driver,jdbc_url,user_name,password from database_info";
private DruidProperties druidProperties;
public DataBaseInfoDao(DruidProperties druidProperties) {
this.druidProperties = druidProperties;
}
/**
* 查询所有数据源列表
*
* @author fengshuonan
* @Date 2019-05-04 20:30
*/
public Map<String, DruidProperties> getAllDataBaseInfo() {
Map<String, DruidProperties> dataSourceList = new HashMap<>();
try {
Class.forName(druidProperties.getDriverClassName());
Connection conn = DriverManager.getConnection(
druidProperties.getUrl(), druidProperties.getUsername(), druidProperties.getPassword());
PreparedStatement preparedStatement = conn.prepareStatement(MYSQL_SQL_LIST);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
DruidProperties druidProperties = createDruidProperties(resultSet);
String dbName = resultSet.getString("db_name");
dataSourceList.put(dbName, druidProperties);
}
return dataSourceList;
} catch (Exception ex) {
throw new DataSourceInitException(DataSourceInitException.ExEnum.QUERY_DATASOURCE_INFO_ERROR);
}
}
/**
* 通过查询结果组装druidProperties
*
* @author fengshuonan
* @Date 2019-06-12 14:22
*/
private DruidProperties createDruidProperties(ResultSet resultSet) {
DruidProperties druidProperties = new DruidProperties();
druidProperties.setTestOnBorrow(true);
druidProperties.setTestOnReturn(true);
try {
druidProperties.setDriverClassName(resultSet.getString("jdbc_driver"));
druidProperties.setUrl(resultSet.getString("jdbc_url"));
druidProperties.setUsername(resultSet.getString("user_name"));
druidProperties.setPassword(resultSet.getString("password"));
} catch (SQLException e) {
throw new DataSourceInitException(DataSourceInitException.ExEnum.QUERY_DATASOURCE_INFO_ERROR);
}
return druidProperties;
}
}
package cn.stylefeng.datasource.container.exception;
import cn.stylefeng.roses.kernel.model.exception.AbstractBaseExceptionEnum;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
/**
* 数据源容器初始化失败异常
*
* @author fengshuonan
* @date 2019-06-12-13:53
*/
public class DataSourceInitException extends ServiceException {
public DataSourceInitException(AbstractBaseExceptionEnum exception) {
super(exception);
}
public enum ExEnum implements AbstractBaseExceptionEnum {
DATA_SOURCE_READ_ERROR(500, "获取主数据源异常"),
INIT_DATA_SOURCE_ERROR(500, "初始化数据源异常"),
QUERY_DATASOURCE_INFO_ERROR(500, "查询数据库中数据源信息错误");
ExEnum(int code, String message) {
this.code = code;
this.message = message;
}
private Integer code;
private String message;
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
}
package cn.stylefeng.datasource.container.listener;
import cn.stylefeng.datasource.container.context.DataSourceContext;
import cn.stylefeng.datasource.container.exception.DataSourceInitException;
import cn.stylefeng.roses.core.config.properties.DruidProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
/**
* 初始化数据源
*
* @author fengshuonan
* @Date 2019-06-12 13:35
*/
@Slf4j
public class DataSourceInitializer implements ApplicationListener<ApplicationPreparedEvent>, Ordered {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
//获取数据源配置
DruidProperties druidProperties = event.getApplicationContext().getBean(DruidProperties.class);
if (druidProperties == null) {
throw new DataSourceInitException(DataSourceInitException.ExEnum.DATA_SOURCE_READ_ERROR);
}
//初始化数据源容器
try {
DataSourceContext.initDataSource(druidProperties);
} catch (Exception e) {
throw new DataSourceInitException(DataSourceInitException.ExEnum.INIT_DATA_SOURCE_ERROR);
}
}
}
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>cn.stylefeng</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId> <artifactId>guns-base-db-container</artifactId>
<version>1.0.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -13,15 +13,12 @@ ...@@ -13,15 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package cn.stylefeng.guns.sys.config.datasource.multi; package cn.stylefeng.guns.sys.config.datasource;
import cn.stylefeng.roses.core.config.properties.DruidProperties; import cn.stylefeng.roses.core.config.properties.DruidProperties;
import cn.stylefeng.roses.core.mutidatasource.aop.MultiSourceExAop; import cn.stylefeng.roses.core.mutidatasource.aop.MultiSourceExAop;
import cn.stylefeng.roses.core.util.ToolUtil;
import com.atomikos.jdbc.AtomikosDataSourceBean; import com.atomikos.jdbc.AtomikosDataSourceBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -29,6 +26,8 @@ import org.springframework.context.annotation.Primary; ...@@ -29,6 +26,8 @@ import org.springframework.context.annotation.Primary;
import javax.sql.DataSource; import javax.sql.DataSource;
import static cn.stylefeng.datasource.container.context.DataSourceContext.MASTER_DATASOURCE_NAME;
/** /**
* 多数据源配置<br/> * 多数据源配置<br/>
* <p> * <p>
...@@ -38,9 +37,7 @@ import javax.sql.DataSource; ...@@ -38,9 +37,7 @@ import javax.sql.DataSource;
* @Date 2017/5/20 21:58 * @Date 2017/5/20 21:58
*/ */
@Configuration @Configuration
@ConditionalOnProperty(prefix = "guns.muti-datasource", name = "open", havingValue = "true") public class DataSourceConfig {
@MapperScan(basePackages = {"cn.stylefeng.guns.sys.modular.*.mapper", "cn.stylefeng.guns.generator.modular.mapper", "cn.stylefeng.guns.modular.*.mapper"}, sqlSessionTemplateRef = "gunsSqlSessionTemplate")
public class MultiDataSourceConfig {
/** /**
* 默认主数据源配置 * 默认主数据源配置
...@@ -53,35 +50,20 @@ public class MultiDataSourceConfig { ...@@ -53,35 +50,20 @@ public class MultiDataSourceConfig {
} }
/** /**
* 多数据源配置
*/
@Bean
@ConfigurationProperties(prefix = "guns.muti-datasource")
public DruidProperties mutiDataSourceProperties() {
return new DruidProperties();
}
/**
* 主数据源实例 * 主数据源实例
*/ */
@Primary @Primary
@Bean @Bean
public DataSource dataSourcePrimary(@Qualifier("druidProperties") DruidProperties druidProperties) { public DataSource dataSourcePrimary(@Qualifier("druidProperties") DruidProperties druidProperties) {
if (ToolUtil.isOneEmpty(druidProperties, druidProperties.getDataSourceName())) {
throw new IllegalArgumentException("初始化OptionalSqlSessionTemplate错误!请设置spring.datasource.data-source-name属性的值!");
}
return createDataSource(druidProperties.getDataSourceName(), druidProperties);
}
/** AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
* 第二个数据源实例 atomikosDataSourceBean.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
*/ atomikosDataSourceBean.setUniqueResourceName(MASTER_DATASOURCE_NAME);
@Bean atomikosDataSourceBean.setMaxPoolSize(20);
public DataSource dataSourceBusiness(@Qualifier("mutiDataSourceProperties") DruidProperties mutiDataSourceProperties) { atomikosDataSourceBean.setBorrowConnectionTimeout(60);
if (ToolUtil.isOneEmpty(mutiDataSourceProperties, mutiDataSourceProperties.getDataSourceName())) { atomikosDataSourceBean.setXaProperties(druidProperties.createProperties());
throw new IllegalArgumentException("初始化OptionalSqlSessionTemplate错误!请设置spring.muti-datasource.data-source-name属性的值!");
} return atomikosDataSourceBean;
return createDataSource(mutiDataSourceProperties.getDataSourceName(), mutiDataSourceProperties);
} }
/** /**
...@@ -92,16 +74,4 @@ public class MultiDataSourceConfig { ...@@ -92,16 +74,4 @@ public class MultiDataSourceConfig {
return new MultiSourceExAop(); return new MultiSourceExAop();
} }
/**
* 数据源创建模板
*/
private static DataSource createDataSource(String dataSourceName, DruidProperties druidProperties) {
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
atomikosDataSourceBean.setUniqueResourceName(dataSourceName);
atomikosDataSourceBean.setMaxPoolSize(20);
atomikosDataSourceBean.setBorrowConnectionTimeout(60);
atomikosDataSourceBean.setXaProperties(druidProperties.createProperties());
return atomikosDataSourceBean;
}
} }
\ No newline at end of file
...@@ -2,17 +2,23 @@ package cn.stylefeng.guns.sys.config.datasource; ...@@ -2,17 +2,23 @@ package cn.stylefeng.guns.sys.config.datasource;
import cn.stylefeng.guns.sys.core.shiro.ShiroKit; import cn.stylefeng.guns.sys.core.shiro.ShiroKit;
import cn.stylefeng.roses.core.metadata.CustomMetaObjectHandler; import cn.stylefeng.roses.core.metadata.CustomMetaObjectHandler;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* mp的插件拓展 * mp的插件拓展和资源扫描
* *
* @author fengshuonan * @author fengshuonan
* @Date 2019/5/10 21:33 * @Date 2019/5/10 21:33
*/ */
@Configuration @Configuration
public class MpPluginsConfig { @MapperScan(basePackages = {"cn.stylefeng.guns.sys.modular.*.mapper",
"cn.stylefeng.guns.generator.modular.mapper",
"cn.stylefeng.guns.modular.*.mapper",
"cn.stylefeng.guns.sms.modular.mapper",
"cn.stylefeng.guns.oauth.modular.mapper"})
public class PluginsConfig {
/** /**
* 拓展核心包中的字段包装器 * 拓展核心包中的字段包装器
......
/**
* Copyright 2018-2020 stylefeng & fengshuonan (sn93@qq.com)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.sys.config.datasource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* 多数据源配置,多数据源配置因为和单数据源冲突,所以现在默认版本删除了多数据源配置
* <p>
* 可参考 https://gitee.com/stylefeng/guns/tree/multi-datasource/
*
* @author stylefeng
* @Date 2017/5/20 21:58
*/
@Configuration
@ConditionalOnProperty(prefix = "guns.muti-datasource", name = "open", havingValue = "false", matchIfMissing = true)
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(basePackages = {"cn.stylefeng.guns.sys.modular.*.mapper",
"cn.stylefeng.guns.generator.modular.mapper",
"cn.stylefeng.guns.modular.*.mapper",
"cn.stylefeng.guns.sms.modular.mapper",
"cn.stylefeng.guns.oauth.modular.mapper"})
public class SingleDataSourceConfig {
}
...@@ -13,13 +13,14 @@ ...@@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package cn.stylefeng.guns.sys.config.datasource.multi; package cn.stylefeng.guns.sys.config.datasource;
import cn.stylefeng.datasource.container.context.DataSourceContext;
import cn.stylefeng.datasource.container.context.SqlSessionFactoryContext;
import cn.stylefeng.datasource.container.exception.DataSourceInitException;
import cn.stylefeng.roses.core.config.properties.DruidProperties; import cn.stylefeng.roses.core.config.properties.DruidProperties;
import cn.stylefeng.roses.core.mutidatasource.mybatis.OptionalSqlSessionTemplate; import cn.stylefeng.roses.core.mutidatasource.mybatis.OptionalSqlSessionTemplate;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException; import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.core.config.GlobalConfig;
...@@ -31,20 +32,18 @@ import org.apache.ibatis.plugin.Interceptor; ...@@ -31,20 +32,18 @@ import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.stylefeng.datasource.container.context.DataSourceContext.MASTER_DATASOURCE_NAME;
/** /**
* 多数据源配置<br/> * 多数据源配置<br/>
* <p> * <p>
...@@ -55,33 +54,24 @@ import java.util.Map; ...@@ -55,33 +54,24 @@ import java.util.Map;
*/ */
@Slf4j @Slf4j
@Configuration @Configuration
@ConditionalOnProperty(prefix = "guns.muti-datasource", name = "open", havingValue = "true") public class SqlSessionFactoryConfig {
public class MultiSqlSessionFactoryConfig {
private final MybatisPlusProperties properties; private final MybatisPlusProperties properties;
private final Interceptor[] interceptors; private final Interceptor[] interceptors;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider; private final DatabaseIdProvider databaseIdProvider;
private final List<ConfigurationCustomizer> configurationCustomizers;
private final ApplicationContext applicationContext; private final ApplicationContext applicationContext;
public MultiSqlSessionFactoryConfig(MybatisPlusProperties properties, public SqlSessionFactoryConfig(MybatisPlusProperties properties,
ObjectProvider<Interceptor[]> interceptorsProvider, ObjectProvider<Interceptor[]> interceptorsProvider,
ResourceLoader resourceLoader,
ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<DatabaseIdProvider> databaseIdProvider,
ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,
ApplicationContext applicationContext) { ApplicationContext applicationContext) {
this.properties = properties; this.properties = properties;
this.interceptors = interceptorsProvider.getIfAvailable(); this.interceptors = interceptorsProvider.getIfAvailable();
this.resourceLoader = resourceLoader;
this.databaseIdProvider = databaseIdProvider.getIfAvailable(); this.databaseIdProvider = databaseIdProvider.getIfAvailable();
this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
...@@ -95,37 +85,43 @@ public class MultiSqlSessionFactoryConfig { ...@@ -95,37 +85,43 @@ public class MultiSqlSessionFactoryConfig {
} }
/** /**
* 第二个sqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactoryBusiness(@Qualifier("dataSourceBusiness") DataSource dataSource) {
return createSqlSessionFactory(dataSource);
}
/**
* 多数据源sqlSessionTemplate切换模板 * 多数据源sqlSessionTemplate切换模板
*/ */
@Bean(name = "gunsSqlSessionTemplate") @Bean(name = "gunsSqlSessionTemplate")
public OptionalSqlSessionTemplate gunsSqlSessionTemplate(@Qualifier("sqlSessionFactoryPrimary") SqlSessionFactory sqlSessionFactoryPrimary, public OptionalSqlSessionTemplate gunsSqlSessionTemplate(@Qualifier("sqlSessionFactoryPrimary") SqlSessionFactory sqlSessionFactoryPrimary,
@Qualifier("sqlSessionFactoryBusiness") SqlSessionFactory sqlSessionFactoryBusiness, @Qualifier("druidProperties") DruidProperties druidProperties) {
@Qualifier("druidProperties") DruidProperties druidProperties, //初始化数据源容器
@Qualifier("mutiDataSourceProperties") DruidProperties mutiDataSourceProperties) { try {
if (ToolUtil.isOneEmpty(druidProperties, druidProperties.getDataSourceName())) { DataSourceContext.initDataSource(druidProperties);
throw new IllegalArgumentException("初始化OptionalSqlSessionTemplate错误!请设置spring.datasource.data-source-name属性的值!"); } catch (Exception e) {
throw new DataSourceInitException(DataSourceInitException.ExEnum.INIT_DATA_SOURCE_ERROR);
} }
if (ToolUtil.isOneEmpty(mutiDataSourceProperties, mutiDataSourceProperties.getDataSourceName())) { //先添加主数据源
throw new IllegalArgumentException("初始化OptionalSqlSessionTemplate错误!请设置spring.muti-datasource.data-source-name属性的值!"); SqlSessionFactoryContext.addSqlSessionFactory(MASTER_DATASOURCE_NAME, sqlSessionFactoryPrimary);
//获取数据库的数据源
Map<String, DataSource> dataSources = DataSourceContext.getDataSources();
//创建其他sqlSessionFactory
for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
String dbName = entry.getKey();
DataSource dataSource = entry.getValue();
//如果是主数据源,跳过,否则会冲突
if (MASTER_DATASOURCE_NAME.equals(dbName)) {
continue;
} else {
SqlSessionFactory sqlSessionFactory = createSqlSessionFactory(dataSource);
SqlSessionFactoryContext.addSqlSessionFactory(dbName, sqlSessionFactory);
}
} }
Map<Object, SqlSessionFactory> sqlSessionFactoryMap = new HashMap<>(); return new OptionalSqlSessionTemplate(sqlSessionFactoryPrimary, SqlSessionFactoryContext.getSqlSessionFactorys());
sqlSessionFactoryMap.put(druidProperties.getDataSourceName(), sqlSessionFactoryPrimary);
sqlSessionFactoryMap.put(mutiDataSourceProperties.getDataSourceName(), sqlSessionFactoryBusiness);
return new OptionalSqlSessionTemplate(sqlSessionFactoryPrimary, sqlSessionFactoryMap);
} }
/** /**
* 创建数据源 * 创建SqlSessionFactory
*/ */
private SqlSessionFactory createSqlSessionFactory(DataSource dataSource) { private SqlSessionFactory createSqlSessionFactory(DataSource dataSource) {
try { try {
......
package cn.stylefeng.guns.generator.modular.entity; package cn.stylefeng.guns.generator.modular.entity;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.IdType; import lombok.Data;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
/** /**
* <p> * <p>
...@@ -17,6 +15,7 @@ import java.io.Serializable; ...@@ -17,6 +15,7 @@ import java.io.Serializable;
* @since 2019-05-11 * @since 2019-05-11
*/ */
@TableName("database_info") @TableName("database_info")
@Data
public class DatabaseInfo implements Serializable { public class DatabaseInfo implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
...@@ -58,78 +57,15 @@ public class DatabaseInfo implements Serializable { ...@@ -58,78 +57,15 @@ public class DatabaseInfo implements Serializable {
private String jdbcUrl; private String jdbcUrl;
/** /**
* 备注
*/
@TableField("remarks")
private String remarks;
/**
* 创建时间 * 创建时间
*/ */
@TableField(value = "create_time", fill = FieldFill.INSERT) @TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime; private Date createTime;
public Long getDbId() {
return dbId;
}
public void setDbId(Long dbId) {
this.dbId = dbId;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getJdbcDriver() {
return jdbcDriver;
}
public void setJdbcDriver(String jdbcDriver) {
this.jdbcDriver = jdbcDriver;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "DatabaseInfo{" +
"dbId=" + dbId +
", dbName=" + dbName +
", jdbcDriver=" + jdbcDriver +
", userName=" + userName +
", password=" + password +
", jdbcUrl=" + jdbcUrl +
", createTime=" + createTime +
"}";
}
} }
...@@ -10,12 +10,13 @@ ...@@ -10,12 +10,13 @@
<result column="user_name" property="userName"/> <result column="user_name" property="userName"/>
<result column="password" property="password"/> <result column="password" property="password"/>
<result column="jdbc_url" property="jdbcUrl"/> <result column="jdbc_url" property="jdbcUrl"/>
<result column="remarks" property="remarks"/>
<result column="create_time" property="createTime"/> <result column="create_time" property="createTime"/>
</resultMap> </resultMap>
<!-- 通用查询结果列 --> <!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <sql id="Base_Column_List">
db_id AS "dbId", db_name AS "dbName", jdbc_driver AS "jdbcDriver", user_name AS "userName", password AS "password", jdbc_url AS "jdbcUrl", create_time AS "createTime" db_id AS "dbId", db_name AS "dbName", jdbc_driver AS "jdbcDriver", user_name AS "userName", password AS "password", jdbc_url AS "jdbcUrl", remarks AS "remarks", create_time AS "createTime"
</sql> </sql>
<select id="customList" resultType="cn.stylefeng.guns.generator.modular.model.result.DatabaseInfoResult" parameterType="cn.stylefeng.guns.generator.modular.model.params.DatabaseInfoParam"> <select id="customList" resultType="cn.stylefeng.guns.generator.modular.model.result.DatabaseInfoResult" parameterType="cn.stylefeng.guns.generator.modular.model.params.DatabaseInfoParam">
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
*/ */
package cn.stylefeng.guns.modular.demos.controller; package cn.stylefeng.guns.modular.demos.controller;
import cn.stylefeng.guns.modular.demos.service.TestMultiDbService; import cn.stylefeng.guns.modular.demos.service.TranTestService;
import cn.stylefeng.roses.core.base.controller.BaseController; import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.reqres.response.SuccessResponseData; import cn.stylefeng.roses.core.reqres.response.SuccessResponseData;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -30,16 +30,22 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -30,16 +30,22 @@ import org.springframework.web.bind.annotation.RestController;
*/ */
@RestController @RestController
@RequestMapping("/multi") @RequestMapping("/multi")
public class TestMultiController extends BaseController { public class TestMultiTranController extends BaseController {
@Autowired @Autowired
private TestMultiDbService testMultiDbService; private TranTestService testMultiDbService;
@RequestMapping("") @RequestMapping("/success")
public Object auth() { public Object testSuccess() {
testMultiDbService.beginTest(); testMultiDbService.beginTest();
return SuccessResponseData.success(); return SuccessResponseData.success();
} }
@RequestMapping("/fail")
public Object testFail() {
testMultiDbService.beginTestFail();
return SuccessResponseData.success();
}
} }
/**
* Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.stylefeng.guns.modular.demos.controller;
import cn.stylefeng.guns.modular.demos.service.TranTestService;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.reqres.response.SuccessResponseData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试单数据源回滚
*
* @author stylefeng
* @Date 2018/7/20 23:39
*/
@RestController
@RequestMapping("/single")
public class TestSingleTranController extends BaseController {
@Autowired
private TranTestService testMultiDbService;
@RequestMapping("/success")
public Object testSuccess() {
testMultiDbService.testSingleSuccess();
return SuccessResponseData.success();
}
@RequestMapping("/fail")
public Object testFail() {
testMultiDbService.testSingleFail();
return SuccessResponseData.success();
}
}
...@@ -25,7 +25,7 @@ public class GunsDbService extends ServiceImpl<UserMapper, User> { ...@@ -25,7 +25,7 @@ public class GunsDbService extends ServiceImpl<UserMapper, User> {
@Autowired @Autowired
private UserService userService; private UserService userService;
@DataSource(name = "gunsdb") @DataSource(name = "master")
public void gunsdb() { public void gunsdb() {
User user = new User(); User user = new User();
user.setAccount(RandomUtil.randomString(5)); user.setAccount(RandomUtil.randomString(5));
......
...@@ -25,7 +25,7 @@ public class OtherDbService extends ServiceImpl<UserMapper, User> { ...@@ -25,7 +25,7 @@ public class OtherDbService extends ServiceImpl<UserMapper, User> {
@Autowired @Autowired
private UserService userService; private UserService userService;
@DataSource(name = "otherdb") @DataSource(name = "test")
public void otherdb() { public void otherdb() {
User user = new User(); User user = new User();
user.setAccount(RandomUtil.randomString(5)); user.setAccount(RandomUtil.randomString(5));
......
package cn.stylefeng.guns.modular.demos.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* <p>
* 测试多数据源回滚的例子
* </p>
*
* @author stylefeng
* @since 2018-12-07
*/
@Service
public class TestMultiDbService {
@Autowired
private GunsDbService gunsDbService;
@Autowired
private OtherDbService otherDbService;
@Transactional(rollbackFor = Exception.class)
public void beginTest() {
gunsDbService.gunsdb();
otherDbService.otherdb();
// int i = 1 / 0;
}
}
package cn.stylefeng.guns.modular.demos.service;
import cn.hutool.core.util.RandomUtil;
import cn.stylefeng.guns.sys.modular.system.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* <p>
* 测试数据源能否回滚的例子
* </p>
*
* @author stylefeng
* @since 2018-12-07
*/
@Service
public class TranTestService {
@Autowired
private GunsDbService gunsDbService;
@Autowired
private OtherDbService otherDbService;
@Transactional(rollbackFor = Exception.class)
public void testSingleSuccess() {
User user = new User();
user.setAccount(RandomUtil.randomString(5));
user.setPassword(RandomUtil.randomString(5));
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
user.setCreateUser(1L);
user.setUpdateUser(1L);
gunsDbService.save(user);
User user2 = new User();
user2.setAccount(RandomUtil.randomString(5));
user2.setPassword(RandomUtil.randomString(5));
user2.setCreateTime(new Date());
user2.setUpdateTime(new Date());
user2.setCreateUser(1L);
user2.setUpdateUser(1L);
gunsDbService.save(user2);
}
@Transactional(rollbackFor = Exception.class)
public void testSingleFail() {
User user = new User();
user.setAccount(RandomUtil.randomString(5));
user.setPassword(RandomUtil.randomString(5));
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
user.setCreateUser(1L);
user.setUpdateUser(1L);
gunsDbService.save(user);
User user2 = new User();
user2.setAccount(RandomUtil.randomString(5));
user2.setPassword(RandomUtil.randomString(5));
user2.setCreateTime(new Date());
user2.setUpdateTime(new Date());
user2.setCreateUser(1L);
user2.setUpdateUser(1L);
gunsDbService.save(user2);
int i = 1 / 0;
}
@Transactional(rollbackFor = Exception.class)
public void beginTest() {
gunsDbService.gunsdb();
otherDbService.otherdb();
}
@Transactional(rollbackFor = Exception.class)
public void beginTestFail() {
gunsDbService.gunsdb();
otherDbService.otherdb();
int i = 1 / 0;
}
}
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
# username: root # username: root
# password: root # password: root
# filters: wall,mergeStat # filters: wall,mergeStat
# data-source-name: gunsdb
#SQLServer配置 #SQLServer配置
#spring: #spring:
...@@ -16,7 +15,6 @@ ...@@ -16,7 +15,6 @@
# username: root # username: root
# password: root # password: root
# filters: wall,mergeStat # filters: wall,mergeStat
# data-source-name: gunsdb
#PostgreSQL配置 #PostgreSQL配置
#spring: #spring:
...@@ -26,7 +24,6 @@ ...@@ -26,7 +24,6 @@
# username: root # username: root
# password: root # password: root
# filters: wall,mergeStat # filters: wall,mergeStat
# data-source-name: gunsdb
# Mysql数据库 # Mysql数据库
spring: spring:
...@@ -36,7 +33,6 @@ spring: ...@@ -36,7 +33,6 @@ spring:
username: root username: root
password: root password: root
filters: wall,mergeStat filters: wall,mergeStat
data-source-name: gunsdb
# 邮件发送配置(改为自己的账号和密码) # 邮件发送配置(改为自己的账号和密码)
mail: mail:
...@@ -45,16 +41,6 @@ spring: ...@@ -45,16 +41,6 @@ spring:
username: sn93@qq.com username: sn93@qq.com
password: xxxpassword password: xxxpassword
# 多数据源情况的配置
guns:
muti-datasource:
open: false
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/guns_test_db?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT
username: root
password: root
data-source-name: otherdb
# 阿里云短信发送配置 # 阿里云短信发送配置
aliyun: aliyun:
sms: sms:
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
# username: GUNS # username: GUNS
# password: GUNS # password: GUNS
# filters: wall,mergeStat # filters: wall,mergeStat
# data-source-name: gunsdb
#SQLServer配置 #SQLServer配置
#spring: #spring:
...@@ -16,7 +15,6 @@ ...@@ -16,7 +15,6 @@
# username: root # username: root
# password: root # password: root
# filters: wall,mergeStat # filters: wall,mergeStat
# data-source-name: gunsdb
#PostgreSQL配置 #PostgreSQL配置
#spring: #spring:
...@@ -26,7 +24,6 @@ ...@@ -26,7 +24,6 @@
# username: root # username: root
# password: root # password: root
# filters: wall,mergeStat # filters: wall,mergeStat
# data-source-name: gunsdb
# Mysql数据库 # Mysql数据库
spring: spring:
...@@ -36,9 +33,6 @@ spring: ...@@ -36,9 +33,6 @@ spring:
username: root username: root
password: root password: root
filters: wall,mergeStat filters: wall,mergeStat
data-source-name: gunsdb
test-on-borrow: true
test-on-return: true
# 邮件发送配置(改为自己的账号和密码) # 邮件发送配置(改为自己的账号和密码)
mail: mail:
...@@ -47,19 +41,6 @@ spring: ...@@ -47,19 +41,6 @@ spring:
username: sn93@qq.com username: sn93@qq.com
password: xxxpassword password: xxxpassword
# 多数据源情况的配置
guns:
muti-datasource:
open: true
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/guns_test_db?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT
username: root
password: root
data-source-name: otherdb
test-on-borrow: true
test-on-return: true
# 阿里云短信发送配置 # 阿里云短信发送配置
aliyun: aliyun:
sms: sms:
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<modules> <modules>
<module>guns-base</module> <module>guns-base</module>
<module>guns-base-db-container</module>
<module>guns-base-sms</module> <module>guns-base-sms</module>
<module>guns-base-email</module> <module>guns-base-email</module>
<module>guns-base-timers</module> <module>guns-base-timers</module>
...@@ -63,7 +64,7 @@ ...@@ -63,7 +64,7 @@
<dependency> <dependency>
<groupId>cn.stylefeng.roses</groupId> <groupId>cn.stylefeng.roses</groupId>
<artifactId>kernel-core</artifactId> <artifactId>kernel-core</artifactId>
<version>1.2.2</version> <version>1.2.4</version>
</dependency> </dependency>
<!--数据库驱动,可根据自己需要自行删减--> <!--数据库驱动,可根据自己需要自行删减-->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment