在使用 MyBatis 查询数据库时,偶尔会出现短时间高频查询的情况。或者,会被短时间高频率查询的数据需要通过另一个微服务的接口来获取。显而易见,高频率的查询数据库,或者高频率的调用微服务的接口,是会对性能产生一定影响的。
在这种情况下,或许可以考虑将相关的数据一次性全部查询出来,然后根据某一列作为 key,将其存放在一个 Map 中,把这个 Map 当成一个临时的缓存。
示例数据
假设有这样的一组数据,其中保存了某公司的一系列基地的信息,包括基地名称、基地代号,和基地所在的区。
id |
base_name |
base_code |
location |
1 |
梅陇 |
ML |
徐汇区 |
2 |
富锦路 |
FJL |
宝山区 |
3 |
龙阳路 |
LYL |
浦东新区 |
4 |
北翟路 |
BDL |
普陀区 |
5 |
川沙 |
CS |
浦东新区 |
6 |
石龙路 |
SLL |
闵行区 |
代码
MyBatis 查询的代码还是同往常一样,一个 SELECT 查询,返回类型就是这个表对应的实体类。
1 2 3 4 5 6 7 8 9 10 11 12
| <select id="queryBaseByNameInMap" resultType="com.boris1993.demoapp.entity.BaseDTO"> SELECT `id`, `base_name`, `base_code`, `location` FROM `base` WHERE del_flag = '0' <if test="baseName != null and baseName != ''"> AND `base_name` = #{baseName} </if> </select>
|
但是在 Mapper 接口中,需要在对应的方法上面加上 @MapKey()
注解。这个注解向 MyBatis 指明了使用实体的哪一个属性 (而不是列名) 作为 Map 的 key。
1 2
| @MapKey("baseName") Map<String, BaseDTO> queryBaseByNameInMap(@Param("baseName") String baseName);
|
执行结果
编写 service、controller 等部分不是本文重点,按下不表。在不传递 baseName
时,就可以查出这样子的数据了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| { "北翟路": { "id": "4", "baseName": "北翟路", "baseCode": "BDL", "location": "普陀区" }, "龙阳路": { "id": "3", "baseName": "龙阳路", "baseCode": "LYL", "location": "浦东新区" }, "梅陇": { "id": "1", "baseName": "梅陇", "baseCode": "ML", "location": "徐汇区" }, "富锦路": { "id": "2", "baseName": "富锦路", "baseCode": "FJL", "location": "宝山区" }, "石龙路": { "id": "6", "baseName": "石龙路", "baseCode": "SLL", "location": "闵行区" }, "川沙": { "id": "5", "baseName": "川沙", "baseCode": "CS", "location": "浦东新区" } }
|
有什么用呢
试想一下,在某个表中,只保存了相关基地的名字,但是在业务中又需要返回这个基地的代号等信息,那么就可以这么做了:
1 2 3 4 5 6 7 8 9 10 11
| Map<String, BaseDTO> bases = baseDataFeignClient.queryBaseByNameInMap();
List<SomethingOutputVO> aListOfSomething = fetchAListOfSomething();
for (SomethingOutputVO item : aListOfSomething) { item.setBaseCode(bases.get(item.getBaseName()).get("baseCode")); }
|
此时,这个 Map 就变成了一个小的缓存,避免了在循环中反复查询数据库或者反复调用微服务接口的问题。