能否复用同一Kotlin数据类适配Redis OM与Exposed SQL以避免冗余映射?
能否复用同一Kotlin数据类适配Redis OM与Exposed SQL以避免冗余映射?
嘿,这个问题我太有共鸣了——我之前在Kotlin项目里用Exposed+Redis OM的时候,也纠结过要不要维护两套几乎一样的数据类!先给你拆解一下两种方案的利弊,再给你实际的建议:
首先,能不能复用同一个类?当然可以!
其实你的场景里,复用是完全可行的,而且能立刻消除冗余。因为:
- Exposed手动映射数据的时候,根本不关心你的数据类有没有其他注解(比如Redis OM的
@Document、@Id这些)——你只是把查询结果的字段值手动塞到数据类里而已,注解对Exposed来说完全透明。 - Redis OM只需要它的注解标记字段,其他的
Serializable或者字段名,只要和你的存储逻辑匹配就行,不会和Exposed冲突。
你可以把两个类合并成一个,同时带上Redis OM注解和Serializable,比如:
@Serializable @Document("Train", indexName = "TrainIdx") data class TrainModel( // 统一字段名,避免映射时的字段转换 @Id @AutoComplete @AutoCompletePayload(fields = ["number", "name"]) val number: String, @Indexed @AutoComplete @AutoCompletePayload(fields = ["number", "name"]) val name: String, val srcDep: Int, val destArr: Int, val runDays: Int, @Indexed val type: Int, )
这样一来,你查询Postgres的时候直接映射到TrainModel,之后不用任何转换就能直接存到Redis:
val results = filteredQuery.map { TrainModel( number = it[TrainTable.number], name = it[TrainTable.name], runDays = it[TrainTable.runDays], srcDep = it[sourceSchedule[ScheduleTable.std]], destArr = it[destSchedule[ScheduleTable.sta]], type = it[TrainTable.trainType] ) } // 直接存Redis,不需要toRedisTrains()了 redisTemplate.saveAll(results)
一下子就省掉了映射函数和第二个类的维护成本,爽得很!
那什么时候应该坚持分开两个类?
复用虽然香,但如果你的项目有这些情况,分开反而更稳妥:
- 未来大概率会有结构差异:现在两个模型看起来一样,但SQL是持久化全量业务数据,Redis是做快速查询/ autocomplete的缓存。以后很可能会出现:
- Postgres里加了敏感字段(比如内部备注),绝对不能放到Redis里;
- Redis里需要加专门的索引字段(比如把
srcDep和destArr拼成一个字符串做联合查询),但Postgres根本不需要这个字段。
这时候分开的类可以各自演化,不会互相干扰。
- 想保持数据层的职责边界:SQL模型是“数据库实体”的映射,Redis模型是“缓存查询模型”,分开的话,每个类的职责更清晰——其他同事看代码的时候,一眼就知道哪个类对应哪个存储层,不会搞混。
- 注解冲突风险:虽然现在Redis OM和Exposed的注解不冲突,但如果以后你用了Exposed的自动实体映射(比如
Entity类),或者Redis OM更新了注解规则,万一出现冲突,分开的类能立刻隔离问题。
给你的实际建议
没有绝对的“最佳实践”,看你的项目阶段:
- 如果是小项目/快速迭代的项目,先复用!现在省下来的时间能用来做更重要的功能,等以后真的需要拆分的时候,再复制一份类、去掉不需要的注解、加个简单的映射函数就行——这个成本很低。
- 如果是中大型项目/长期维护的项目,建议分开!虽然现在多写几行代码,但以后需求变化的时候,你会感谢当初的“冗余”——不用改完SQL模型又要改Redis模型,还得排查有没有漏改的映射逻辑。
哦对了,要是选复用的话,记得把字段名统一(比如你原来的RedisTrains用code,TrainCache用number,统一成一个名字),这样能避免映射时的字段转换,进一步减少冗余。
内容来源于stack exchange
相关产品推荐
相关产品推荐

