今天遇到一个场景,公司的消息因为过多。所以做成了分库的情况。一个月内的数据存在当前表中。一个月之前的数据存放在备份表中。然后把主库和备份库做成多数据源的形式。在查询的时候如果主库表中没有就去备份库中查询。
其实说起来好像挺高端的。但是实现上很简单,下面是具体的实现。
数据源配置
导包,基本项目架构啥的我就不多说了。直接上配置文件。我这里是用yml的形式:
spring:
datasource:
# Druid数据库连接池
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:clickhouse://xxx:8123/test
driverClassName: com.clickhouse.jdbc.ClickHouseDriver
druid:
first: # 数据源1
# 数据库驱动
driver-class-name: com.clickhouse.jdbc.ClickHouseDriver
url: jdbc:clickhouse://xxx:8123/test
username: default
password: default
second: # 数据源2
# 数据库驱动
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://xxx:3306/test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone= GMT%2B8
username: root
password: 123456
third: # 数据源3
# 数据库驱动
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://xxx:3306/test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone= GMT%2B8
username: root
password: 123456
fourth: # 数据源3
# 数据库驱动
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://XXX:3306/test_b?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: 123456
initial-size: 10
max-active: 100
min-idle: 10
max-wait: 60000
这里所有关于数据库地址和名称我都隐藏了,要根据具体的情况配置。但是如图所示,我们这里配置了四个数据源。第一个是个clickhouse数据库,二三四都是mysql。其中第三个是我说到的消息的主库,第四个是我说的消息的历史库。
sql配置
@DataSource(name = DataSourceNames.THIRD)
Integer if_exist(Map<String, Object> params);
@DataSource(name = DataSourceNames.FOURTH)
Integer if_exist_archive(Map<String, Object> params);
@DataSource(name = DataSourceNames.THIRD)
Map<String, Object> preview(Map<String, Object> params);
@DataSource(name = DataSourceNames.FOURTH)
Map<String, Object> preview_archive(Map<String, Object> params);
注意看上面的代码,第一个方法if_exist 指定的是第三个数据源,我上面说过是消息表的主库。if_exist_archive指定的是第四个数据源,也就是消息表的历史库。
同理下面的两个查询数据的方法一个是主库查询,一个是历史库查询。
sql其实就是很无脑的一个判断是否存在,一个查询数据。
<select id="if_exist" parameterType="map" resultType="int">
SELECT EXISTS(SELECT 1
FROM msg AS b
WHERE FileName = #{filename}
LIMIT 1)
</select>
<select id="if_exist_archive" parameterType="map" resultType="int">
SELECT EXISTS(SELECT 1
FROM msg AS b
WHERE FileName = #{filename}
LIMIT 1)
</select>
<select id="preview" parameterType="map" resultType="map">
SELECT
uncompress(b.Message) AS Message
FROM msg AS b
WHERE FileName = #{filename}
LIMIT 1
</select>
<select id="preview_archive" parameterType="map" resultType="map">
SELECT
uncompress(b.Message) AS Message
FROM msg AS b
WHERE FileName = #{filename}
LIMIT 1
</select>
代码维护切换数据库
上面我们数据源,sql都配置好了。接下来就是代码维护了。理论上就是主库查不到就去历史库查询,使用方法如下:
Map<String, Object> result;
if (msgDao.if_exist(params) > 0) {
result = msgDao.preview(params);
} else {
result = msgDao.preview_archive(params);
};
就这么几行代码就实现了这个功能。
结语
其实这个功能我感觉是会则不难,难则不会。
看到了人家的做法之后恍然大悟,觉得简单的很。可是在这之前我是没有这种类似的想法的。甚至说之前的做法都局限于一个数据库,最多就是分表而已。写起来也没这么简单。两张表需要两个entity和Dao甚至xml。总而言之又学到了一种用法,还是挺开心的。
本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利,每天学习一点点~