多数据源的springboot进行动态连接方案
多数据源是实际开发中很常见的需求,比如同时操作主数据库和从数据库、或者不同业务的数据库,Spring Boot 提供了灵活的配置方式,我会用通俗易懂的方式带你实现。
核心实现思路
实现多数据源的核心是:
配置多个数据源的连接信息(URL、用户名、密码等);
为每个数据源创建独立的 DataSource 实例;
为每个数据源配置对应的 SqlSessionFactory(MyBatis 场景)或 EntityManagerFactory(JPA 场景);
指定不同包 / 类使用对应的数据源(通过注解或配置区分)。
Springboot的基础配置yml设置连接
java
jdbc:
dbType: mysql
url:
ecg: jdbc:mysql://localhost:3306/ecg?serverFTimezone=CTT&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username:
ecg: root
password:
ecg: root
在config获取配置yml内容
java
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "jdbc")
public class JdbcConfig {
@Value("${jdbc.dbType}")
private String dbType;
@Value("${jdbc.url.ecg}")
private String urlEcg;
@Value("${jdbc.username.ecg}")
private String usernameEcg;
@Value("${jdbc.password.ecg}")
private String passwordEcg;
}
Config目录下面的子文件夹properties下的dataconfig.java进行配置
java
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.sql.SQLException;
import java.util.Properties;
@Configuration
public class DataSourceConfig {
@Autowired
private JdbcConfig jdbcConfig;
@Bean(name = "ecg", initMethod = "init", destroyMethod = "close")
public DruidDataSource dataSource_ecg() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(jdbcConfig.getUrlEcg());
druidDataSource.setUsername(jdbcConfig.getUsernameEcg());
druidDataSource.setPassword(jdbcConfig.getPasswordEcg());
druidDataSource.setInitialSize(1);
druidDataSource.setMaxActive(20);
druidDataSource.setMinIdle(3);
druidDataSource.setMaxWait(60000);
druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
druidDataSource.setMinEvictableIdleTimeMillis(300000);
druidDataSource.setValidationQuery("SELECT 1");
druidDataSource.setTestOnBorrow(true);
druidDataSource.setTestOnReturn(false);
druidDataSource.setTestWhileIdle(true);
druidDataSource.setFilters("stat");
druidDataSource.setRemoveAbandoned(true);
druidDataSource.setRemoveAbandonedTimeout(3600);
druidDataSource.setLogAbandoned(true);
Properties properties = new Properties();
properties.put("remarksReporting", "true");
druidDataSource.setConnectProperties(properties);
return druidDataSource;
}
连接数据库表中的动态数据源
java
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "data_source", schema = "")
@DynamicUpdate(true)
@DynamicInsert(true)
@SuppressWarnings("serial")
public class DynamicDataSourceEntity implements java.io.Serializable {
/**id*/
private java.lang.String id;
/**dbKey*/
private java.lang.String dbKey;
/**description*/
private java.lang.String description;
/**driverClass*/
private java.lang.String driverClass;
/**url*/
private java.lang.String url;
/**dbUser*/
private java.lang.String dbUser;
/**dbPassword*/
private java.lang.String dbPassword;
/**dbType*/
private java.lang.String dbType;
/**dbName*/
private java.lang.String dbName;
/**
*方法: 取得java.lang.String
*@return: java.lang.String id
*/
@Id
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "uuid")
@Column(name ="ID",nullable=false,precision=36,length=36)
public java.lang.String getId(){
return this.id;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String id
*/
public void setId(java.lang.String id){
this.id = id;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String dbKey
*/
@Column(name ="DB_KEY",nullable=false,precision=50,length=50)
public java.lang.String getDbKey(){
return this.dbKey;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String dbKey
*/
public void setDbKey(java.lang.String dbKey){
this.dbKey = dbKey;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String description
*/
@Column(name ="DESCRIPTION",nullable=false,precision=50,length=50)
public java.lang.String getDescription(){
return this.description;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String description
*/
public void setDescription(java.lang.String description){
this.description = description;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String driverClass
*/
@Column(name ="DRIVER_CLASS",nullable=false,precision=50,length=50)
public java.lang.String getDriverClass(){
return this.driverClass;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String driverClass
*/
public void setDriverClass(java.lang.String driverClass){
this.driverClass = driverClass;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String url
*/
@Column(name ="URL",nullable=false,precision=100,length=100)
public java.lang.String getUrl(){
return this.url;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String url
*/
public void setUrl(java.lang.String url){
this.url = url;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String dbUser
*/
@Column(name ="DB_USER",nullable=false,precision=50,length=50)
public java.lang.String getDbUser(){
return this.dbUser;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String dbUser
*/
public void setDbUser(java.lang.String dbUser){
this.dbUser = dbUser;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String dbPassword
*/
@Column(name ="DB_PASSWORD",nullable=true,precision=50,length=50)
public java.lang.String getDbPassword(){
return this.dbPassword;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String dbPassword
*/
public void setDbPassword(java.lang.String dbPassword){
this.dbPassword = dbPassword;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String dbType
*/
@Column(name ="DB_TYPE",nullable=true,precision=50,length=50)
public java.lang.String getDbType(){
return this.dbType;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String dbType
*/
public void setDbType(java.lang.String dbType){
this.dbType = dbType;
}
/**
*方法: 取得java.lang.String
*@return: java.lang.String dbName
*/
@Column(name ="DB_NAME",nullable=true,precision=50,length=50)
public java.lang.String getDbName() {
return dbName;
}
/**
*方法: 设置java.lang.String
*@param: java.lang.String dbName
*/
public void setDbName(java.lang.String dbName) {
this.dbName = dbName;
}
}
测试连接情况
java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public class DynamicDBTest extends AbstractUnitTest {
static String dbKey = "ECG_LOCAL";
@Autowired
private CacheServiceI cacheService;
/**
* 定义多数据源配置
*/
@Before
public void initDB(){
DynamicDataSourceEntity dynamicSourceEntity = new DynamicDataSourceEntity();
String driverClassName = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/ecg";
String dbUser = "root";
String dbPassword = "root";
dynamicSourceEntity.setDbKey(dbKey);
dynamicSourceEntity.setDriverClass(driverClassName);
dynamicSourceEntity.setUrl(url);
dynamicSourceEntity.setDbUser(dbUser);
dynamicSourceEntity.setDbPassword(dbPassword);
Map<String, DynamicDataSourceEntity> dynamicDataSourceMap = new HashMap<String, DynamicDataSourceEntity>();
dynamicDataSourceMap.put(dbKey, dynamicSourceEntity);
//缓存数据
cacheService.put(CacheServiceI.FO_CACHE,ResourceUtil.DY_DB_CONFIGS_FOREVER_CACHE_KEY,dynamicDataSourceMap);
}
@Test
public void testInsert() throws Exception {
String id = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 测试查询列表
String sql = "insert ecg (id,name)values(?,'DynamicDBTest-insert') ";
DynamicDBUtil.update(dbKey,sql,id);
System.out.println("-----------testInsert---------");
}
@Test
public void testUpdate() throws Exception {
// 测试查询列表
String sql = "update ecg set name='动态数据库源测试' where id = '4'";
DynamicDBUtil.update(dbKey,sql);
System.out.println("-----------testUpdate---------");
}
@Test
public void testSelectList() throws Exception {
// 测试查询列表
String sql = "select * from ecg";
List<Map<String, Object>> list = DynamicDBUtil.findList(dbKey, sql);
System.out.println("---------------testSelectList------listSize--------"+ list.size());
for (Map<String, Object> mp : list) {
System.out.println(mp.toString());
}
}
@Test
public void testActionEntity(){
String sql = "<#if nlevel gt 2> insert into TEST003(id, sname, nlevel) values ((select maxid from (select ifnull(max(id)+1,1) maxid from TEST003) a),"
+ " :sname, :nlevel)</#if>";
HashMap<String, Object> data = new HashMap<String, Object>();
data.put("sname", "aaa");
data.put("nlevel", 3);
DynamicDBUtil.updateByHash(dbKey, sql, data);
sql = "SELECT * FROM TEST003 WHERE id = :id";data = new HashMap<String, Object>();
data.put("id", 1);
Map<String, Object> aaa = (Map<String, Object>) DynamicDBUtil.findOneByHash(dbKey, sql, data);
System.out.println(aaa.get("sname"));
sql = "SELECT * FROM TEST003 WHERE id >= '${id}'";data = new HashMap<String, Object>();
data.put("id", 2);
List<Test> bbb = DynamicDBUtil.findListEntrysByHash(dbKey, sql, Test.class, data);
System.out.println(bbb);
}
}