最近在独立开发一个小项目,由于只有我一个人负责数据库,后端,前端,部署等所有环境。采用的技术栈是springboot+kotlin+mysql。写的过程中决定抛弃多表关联查询,所有的查询操作都采用单表来进行处理,看下是否可以完整覆盖整个业务。
优缺点
先说优点:
- 不需要额外的bo,vo等转换类。
- 都是单表,效率比较高,且SQL简单,mybatisPlus可以全程覆盖
- 由于采用了缓存,相同的关联字段可以直接复用
缺点:
- 如果单表的数据量很大时,会有一定的效率影响。(因为需要做缓存)
- 页面需要经过二次匹配处理,对加载速度有一定的影响。(实际操作基本无感知)
各种问题:
没有关联表,当需要展示多个表的数据时,需要查询关联表的字典数据,在前端进行匹配。这个时候就需要用到缓存技术,防止频繁调用数据库造成重复资源浪费。
关联表字段显示
后端
主要依赖缓存框架来实现增,删,改对内存数据的动态变化。
1. 配置缓存管理
@Bean
open fun cacheManager(): CacheManager {
val caffeineCacheManager = CaffeineCacheManager()
caffeineCacheManager.setCaffeine(
Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
)
return caffeineCacheManager
}
默认的有效期是10分钟。
2. Service添加对应缓存注解
- 更新数据
- 查询数据
- 新增数据
不做缓存处理,当查询不到时,会走查询数据缓存,为空会走一遍数据库,插入到缓存中。
前端
主要是在页面mounted时,加载我们需要关联数据。等列表需要渲染时,进行id值转换即可。
Vue2值转换匹配
- 列表匹配
<div slot="busSlot" slot-scope="{text}">
{{text == null ? '': busList.find(c => c.id == text).name}}
</div>
<div slot="lineSlot" slot-scope="{text}">
{{text == null ? '': lineList.find(c => c.id == text).name}}
</div>
- map匹配
<div slot="userId" slot-scope="{record}">
{{userMap[record.userId]}}({{record.userId}})
</div>
Map匹配的效率要高于列表匹配,对于数据量大的表可以采用Map匹配。
数据插入
业务中有一个交易表,查询时需要显示关联的线路,车辆,学校三个信息。初始的交易表其实没有该数据。现在需要匹配单表,所以需要进行字段id冗余。分别是(lineId,busId,schoolId),这也是单表比较麻烦的地方。
- 增加字段
- 插入时通过上述的缓存查询到关联的id插入到数据库中
val bus = equipment?.busId?.let { busService.selectOne(it) }
数据查询
查询时就比较简单了,不需要进行关联表查询,通过mybatisPlus进行操作即可。
fun faceTradePage(faceTradeRequest: FaceTradeRequest): Any {
return faceTradeMapper.selectPage(
Page(faceTradeRequest.current.toLong(), faceTradeRequest.size.toLong()),
KtQueryWrapper(FaceTrade::class.java)
.eq(FaceTrade::merId, faceTradeRequest.customerId)
.eq(faceTradeRequest.userId > 0, FaceTrade::userId, faceTradeRequest.userId)
.eq(!faceTradeRequest.equipmentId.isNullOrEmpty(), FaceTrade::terId, faceTradeRequest.equipmentId)
.eq(!faceTradeRequest.schoolCode.isNullOrEmpty(), FaceTrade::schoolCode, faceTradeRequest.schoolCode)
.eq(faceTradeRequest.lineId != null, FaceTrade::lineId, faceTradeRequest.lineId)
.eq(faceTradeRequest.busId != null, FaceTrade::busId, faceTradeRequest.busId)
.gt(StrUtil.isNotEmpty(faceTradeRequest.startDate), FaceTrade::tradeTime, "${faceTradeRequest.startDate} 00:00:00")
.lt(StrUtil.isNotEmpty(faceTradeRequest.endDate), FaceTrade::tradeTime, "${faceTradeRequest.endDate} 23:59:59")
.orderByDesc(FaceTrade::createTime)
)
}
总结
把后端的一部分工作转移到前端处理,小型项目这样操作还是很方便,便于接口的开发,提升代码开发速度。推荐使用kotlin来开发springboot项目,以较小的代码量,更快的速度完成项目的开发迭代。