时间:2021年11月27日
作者:小蒋聊技术
大家好,欢迎来到小蒋聊技术。小蒋准备和大家一起聊聊技术的那些事。
仅仅看标题,其实这个标题其实并没有什么吸引力,不就是多数据源嘛。
不过,在实际的研发工作中,多数据源却是一个高频需求,必备的一个技能点。小蒋今天就从自己的一个案例中,挑出一个和大家一起来看看。
手动创建jdbcTemplate多数据源
- 业务场景:
老工程再次添加新需求,需要读取另外的一个数据库。
详细说明:有些工程已经稳定运行很久,突然接到新需求,需要升级。例如,从外部A数据库中获取数据。处理后,再保存到本地B数据库中。
这种老工程再次开发的场景,一般来说是小修、小补、小升级。但对于老工程,因为开发时间比较久,但工程已经经过多次维护和时间的检验,已经进入稳定运行状态。
对于这样的场景,如果工程中的数据源(DataSource)是全局性的,千万要注意,可别小升级带来大麻烦。
如果场景相似,小蒋个人的建议是:尽量“多新增,少修改。能不改,就别改”。
- 解决方案:
“手动新建数据源,尽量别影响原始的数据源”。
在Spring Boot中,jdbcTemplate、MyBatis、JPA这三种实现都可以配置多数据源。
其中,MyBatis和JPA是两种主流的实现方式。所以,小蒋今天就准备和大家一起通过“手动”新建jdbcTemplate这种实现方式,一起体验一下“多新增,少修改。能不改,就别改” 这个策略。
- 方案说明:
有些老工程已经开发很久了,当时的工程设计资料可能已经不全了。咱先不聊开发人员是否都在职,就算全部都在职。但是,别小瞧“时间的威力”,研发人员能剩下的记忆也非常有限。这个时候,去修改一个全局的DataSource,其风险是非常大的。所以,如果是“小修、小补、小升级”,这个时候“多新增,少修改。能不改,就别改”这个策略可能更合适。
-
示例:
1.选择Spring Boot版本:
(咱们的“业务场景”是一个老工程,小蒋选择Spring Boot 1.5.6.RELEASE 这个版本)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
2.添加Maven的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!--druid依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
注意:数据库连接池Druid依赖,小蒋选择了druid-spring-boot-starter。优势在于,它是用于帮助使用者在Spring Boot项目中轻松集成Druid数据库连接池和监控的。(druid-spring-boot-starter项目地址)
3.配置数据源:
在application.properties文件中配置“两个”,“新”的数据源。
(注意,这里配置的“新数据源”和老项目里原来“jpa的数据源”,配置的key是不同的。)
spring.datasource.one.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8
spring.datasource.one.username=root
spring.datasource.one.password=12345678
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8
spring.datasource.two.username=root
spring.datasource.two.password=12345678
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
4.新增DataSourceConfig类:
在application.properties配置文件中,我们对数据源做了区分“one”和“tow”。KEY的设置不符合spring boot自动加载的规则,所以需要DataSourceConfig类,我们手动加载。
@Configuration
public class DataSourceConfig {
@Bean
//@Primary 这个注解是设置默认数据源,老项目中原来的数据源应该是默认的。
@ConfigurationProperties(prefix = "spring.datasource.one")
DataSource dsOne() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.two")
DataSource dsTwo() {
return DruidDataSourceBuilder.create().build();
}
}
@ConfigurationProperties是Spring Boot提供的类型安全的属性绑定,通过读取配置文件(例如:application.properties)中的前缀(例如:spring.datasource.one)属性去创建数据源,根据我们的配置我们将会有两个不同的数据源。
5.新增JdbcTemplateConfig类:
接下来我们再通过JdbcTemplateConfig类根据不同的数据源,去创建不同的JdbcTemplate实例
@Configuration
public class JdbcTemplateConfig {
@Bean
JdbcTemplate jdbcTemplateOne(@Qualifier("dsOne") DataSource dsOne) {
return new JdbcTemplate(dsOne);
}
@Bean
JdbcTemplate jdbcTemplateTwo(@Qualifier("dsTwo") DataSource dsTwo) {
return new JdbcTemplate(dsTwo);
}
}
@Qualifier注解,表示按照名称查询。也就是就根据不同的数据源,创建了不同的JdbcTemplate实例。
6.功能验证
通过Controller注入两个不同的JdbcTemplate,这两个JdbcTemplate对应了不同的数据源。
@RestController
public class HelloController {
@Autowired
@Qualifier("jdbcTemplateOne")
JdbcTemplate jdbcTemplateOne;
@Resource(name = "jdbcTemplateTwo")
JdbcTemplate jdbcTemplateTwo;
@GetMapping("/test1")
public Integer getTest1() {
Integer count = jdbcTemplateOne.queryForObject("SELECT count(*) FROM user",Integer.class);
return count;
}
@GetMapping("/test2")
public Integer getTest2() {
Integer count = jdbcTemplateTwo.queryForObject("SELECT count(*) FROM fruit", Integer.class);
return count;
}
小蒋解释一下注入方式:
- 使用JDK提供的@Resource注解,通过byName方式注入。
- 使用Spring提供的@Autowrired注解,配合@Qualifier注解,两者联合方式注入。
(这两种注入方式本质上都是ByName,区别无非就是使用JDK提供的,还是使用Spring提供的而已)
测试地址:
源代码地址:GitHub - loveflywei/study-mulitple-datasource
老/旧系统升级策略
如果你现在是一名工程师,将来想要成为一名架构师。或者你已经是一名架构师了,还想再进一步提升。接下来,小蒋准备为大家分享一些自己工作中的心得和体会。
在大部分互联网公司里,运行的工程和系统,用“不计其数”来形容一点都不算夸张。有无数的工程和系统支撑着公司日常的业务正常运营。
为了满足业务上的各种需求变动,“老/旧系统的升级或改造”是在正常不过的事了。
但是,每面对这种场景,小蒋我仍然是“嘴唇发干、头皮发麻、脸色煞白、胸闷气短、后背发凉、满头大汗”。
小蒋我没病,但是我紧张。面对“老/旧系统升级或改造”的你是不是也有这样相同的经历呢?!
“老/旧系统升级或改造”不求额外有多少性能/功能的提升,但求正常表现。结果因为老/旧系统开发时间久远、研发人员流失、设计资料不足、系统中相互依赖的各种关系,稍微改动,就全是错误。结果一紧张什么“策略”都忘了,只求妈妈带我回家。
关键时刻“紧张”,影响深远,难以估量。
“紧张”人人有,一旦出现,难以消除,只能缓解。有一种说法是,紧张来源于准备不充分加急功近利。
公式:不充分的程度 ✖️ 急功近利的程度 = 紧张程度
解决方案:
通过这个公式,我们可以洞悉紧张的本质,那就是未知的纰漏和风险。之所以会紧张,就是因为“未知感强烈”,再加上“控制感不足”。
也就是说对于“老/旧系统升级或改造”,一般紧张的原因就是:“我对该系统都不知道是什么、而且升级/改造有没有麻烦、有多大麻烦,我都没办法控制”!
小蒋个人建议,对于不熟悉的“老/旧系统升级或改造”,最开始尽量“小修、小补、小升级”。通过这个策略,充分了解“老/旧系统”,减少“不充分程度”。
多使用“多新增,少修改。能不改,就别改”策略,通过这个策略减少“急功近利程度”。
总结:
通过这个道理,我们自己可以举一反三,找到消除紧张的技巧。多读书,充分了解专业知识,减少盲目的开发,增加确定性。开发前要做解决方案设计,方案要落地与纸上。
年龄的增长不可怕,可怕的是从未成长!
感谢大家支持小蒋,小蒋希望和大家共同成长,谢谢。
音频地址:
【20211127】Spring Boot 手动创建多数据源https://www.ximalaya.com/keji/51588599/476708716