多数据源配置使用注解和yml,只需要四步,亲测可用。
环境配置不提版本简直是耍流氓。
所以声明下,工程是在SpringBoot 2.1.8.RELEASE, JDK8环境下调通的。
多数据源的需求:笔者这个微服务负责数据分析,所以微服务除了自己的直连数据库,还需要连接其他的数据库进行合并查询。从下图可以看到服务目前支持连接user数据库和analysis数据库。
如果需求相同、版本相似,下面代码毫不犹豫拿去修改就行,坑已趟平。如果想要看数据库原理的,欢迎看笔者的其他博客。
注释掉的是非必须的配置
@Configuration
@Slf4j
public class DruidDataSourceConfig {
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.initial-size}")
private int initialSize;
@Value("${spring.datasource.min-idle}")
private int minIdle;
@Value("${spring.datasource.max-active}")
private int maxActive;
@Value("${spring.datasource.max-wait}")
private int maxWait;
@Value("${spring.datasource.connectionInitSqls}")
private String connectionInitSqls;
//
// @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
// private int timeBetweenEvictionRunsMillis;
//
// @Value("${spring.datasource.minEvictableIdleTimeMillis}")
// private int minEvictableIdleTimeMillis;
//
// @Value("${spring.datasource.validationQuery}")
// private String validationQuery;
//
// @Value("${spring.datasource.testWhileIdle}")
// private boolean testWhileIdle;
//
// @Value("${spring.datasource.testOnBorrow}")
// private boolean testOnBorrow;
//
// @Value("${spring.datasource.testOnReturn}")
// private boolean testOnReturn;
//
// @Value("${spring.datasource.poolPreparedStatements}")
// private boolean poolPreparedStatements;
//
// @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
// private int maxPoolPreparedStatementPerConnectionSize;
//
// @Value("${spring.datasource.filters}")
// private String filters;
//
// @Value("{spring.datasource.connectionProperties}")
// private String connectionProperties;
/* #####################基础公共配置##################### */
/* #####################analysisdb配置##################### */
@Value("${spring.datasource.analysisdb.url}")
private String analysisUrl;
@Value("${spring.datasource.analysisdb.username}")
private String analysisUsername;
@Value("${spring.datasource.analysisdb.password}")
private String analysisPassword;
@Bean(name = "analysisDataSource")
@Primary // 确定主数据源
public DataSource analysisDataSource() {
log.info("创建analysisDataSource数据源");
return createDataSource(analysisUrl, analysisUsername, analysisPassword);
}
/* #####################userdb配置##################### */
@Value("${spring.datasource.userdb.url}")
private String userUrl;
@Value("${spring.datasource.userdb.username}")
private String userUsername;
@Value("${spring.datasource.userdb.password}")
private String userPassword;
@Bean(name = "userDataSource")
public DataSource userDataSource() {
log.info("创建userDataSource数据源");
return createDataSource(userUrl, userUsername, userPassword);
}
/* #####################DataSource配置##################### */
private DataSource createDataSource(String url, String username, String password) {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
// configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
// datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// datasource.setValidationQuery(validationQuery);
// datasource.setTestWhileIdle(testWhileIdle);
// datasource.setTestOnBorrow(testOnBorrow);
// datasource.setTestOnReturn(testOnReturn);
// datasource.setPoolPreparedStatements(poolPreparedStatements);
// datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
// try {
// datasource.setFilters(filters);
// } catch (SQLException e) {
// e.printStackTrace();
// }
// datasource.setConnectionProperties(connectionProperties);
List connectInitSqls = new ArrayList(){{
add(connectionInitSqls);
}};
datasource.setConnectionInitSqls(connectInitSqls);
return datasource;
}
}
server:
port: 9007
spring:
jpa:
hibernate:
ddl-auto: update
properties:
show_sql: true
format_sql: true
hibernate:
ejb:
# interceptor: 此处是打印sql的配置,非必须
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
# 自定义数据库配置
datasource:
driver-class-name: com.mysql.jdbc.Driver
connectionInitSqls: set names utf8mb4;
initial-size: 10
max-active: 60
min-idle: 5
max-wait: 60
analysisdb:
url: jdbc:mysql://host:3306/analysis?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: username
password: password
userdb:
url: jdbc:mysql://host:3306/user?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: username
password: password
第一个数据库:
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "analysisEntityManagerFactory", // 实体类工厂依赖
transactionManagerRef = "analysisTransactionManager", // 事务依赖
basePackages = "com.xxx.analysis.dao.analysis") // repository类所在的包
@EnableTransactionManagement
@Slf4j
public class AnalysisDBConfig {
@Autowired
private JpaProperties jpaProperties;
@Autowired
@Qualifier("analysisDataSource")
private DataSource dataSource;
@Autowired
private HibernateProperties hibernateProperties;
/*
* 通过LocalContainerEntityManagerFactoryBean来获取EntityManagerFactory实例
*/
@Bean(name = "analysisEntityManagerFactoryBean")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(
EntityManagerFactoryBuilder builder) {
Map properties = hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings());
return builder.dataSource(dataSource).properties(properties)
.packages("com.xxx.analysis.domain.analysis").build();
}
/*
* EntityManagerFactory类似于Hibernate的SessionFactory,mybatis的SqlSessionFactory
* 总之,在执行操作之前,我们总要获取一个EntityManager,这就类似于Hibernate的Session,
* mybatis的sqlSession.
*/
@Bean(name = "analysisEntityManagerFactory")
@Primary
public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder) {
log.info("创建analysisEntityManagerFactory");
return this.entityManagerFactoryBean(builder).getObject();
}
/*
* 配置事务管理器
*/
@Bean(name = "analysisTransactionManager")
@Primary
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
log.info("创建analysisTransactionManager");
return new JpaTransactionManager(this.entityManagerFactory(builder));
}
}
第二个数据库:
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "userEntityManagerFactory",
transactionManagerRef = "userTransactionManager",
basePackages = "com.xxx.analysis.dao.user")
@EnableTransactionManagement
@Slf4j
public class UserDBConfig {
@Autowired
private JpaProperties jpaProperties;
@Autowired
@Qualifier("userDataSource")
private DataSource dataSource;
@Autowired
private HibernateProperties hibernateProperties;
@Bean(name = "userEntityManagerFactoryBean")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(
EntityManagerFactoryBuilder builder) {
Map properties = hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings());
return builder.dataSource(dataSource).properties(properties)
.packages("com.xxx.analysis.domain.user").build();
}
@Bean(name = "userEntityManagerFactory")
public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder) {
log.info("创建userEntityManagerFactory");
return this.entityManagerFactoryBean(builder).getObject();
}
@Bean(name = "userTransactionManager")
@Primary
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
log.info("创建userTransactionManager");
return new JpaTransactionManager(this.entityManagerFactory(builder));
}
}
简单贴一下代码,毕竟不是每个人都熟悉jpa。
下面为analysis的domain层和dao层的代码。
注意,domain和dao的包名要与第三步配置的包名是一致的。
domain:
@Data
@Entity
@Table(name = "test_info")
@Where(clause = "valid = 1")
public class TestInfo extends BaseEntity {
@Column
private String content;
}
dao:
@Repository
public interface TestRepository extends BaseRepository {
}
@NoRepositoryBean
public interface BaseRepository extends JpaRepository, JpaSpecificationExecutor {
}
测试代码,笔者觉得这个很随意,当时随手写了个定时来debug
@Component
@Slf4j
public class DataSchedule {
@Autowired
private UserRepository userRepository;
@Autowired
private TestRepository testRepository;
@Scheduled(cron = "0 * * * * *")
public void autoCalData() {
log.info("start task autoCalData");
TestInfo testInfo = testRepository.findById(1L).get();
UserInfo userInfo = userRepository.findById(680L).get();
log.info("task finish autoCalData");
}
}
最后,限于笔者经验水平有限,欢迎读者就文中的观点提出宝贵的建议和意见。如果想获得更多的学习资源或者想和更多的是技术爱好者一起交流,可以关注我的公众号『全菜工程师小辉』后台回复关键词领取学习资料、进入后端技术交流群和程序员副业群。同时也可以加入程序员副业群Q群:735764906 一起交流。