最近一个产品的开发工作告一段落,本文记录开发过程中遇到的几个印象深刻的问题。
数据库查询排序字段问题
问题一
: 排序字段数据重复问题,有一个列表,按时间排序,但是有大量时间相同,导致不同页数据有重叠。
解决办法
:分页查询处理按时间外,再加一个按主键排序的第二排序字段。
问题二
: 排序字段有空值时,导致结果不稳定。
解决办法
:避开空值,例如设置一个默认值,或者排序多加一列。
MyBatis 缓存问题
多模块开发中,有一个模块 A 只读数据库,它依赖另一个模块 B 对某张表进行修改。模块 A 启动时会读取数据库数据,同时用一个定时器查询最新值。
MyBatis
默认配置了缓存,导致模块 A 怎么都查不到最新数据。
解决办法:对于只读的模块,禁用缓存。配置为:
mybatis-plus:
mapper-locations: classpath*:/mapper/*.xml
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
RestTemplate 超时时间配置
多模块间服务调用时,需要考虑到目标服务器的处理时间,RestTemplate
读取超时时间应该远大于服务器处理的超时时间,保证服务端处理先超时,再返回。
Netty 工作线程资源死锁
有一个多模块通信流程如下:
A 下发数据给 NettyServer
,它的 NIO 处理线程跟接收 B 响应的 NIO 线程是同一个,所以是顺次执行的。
而实际上前者依赖后者更新下发结果,A 下发线程得不到响应结果后超时返回,规则响应线程此时才能继续更新缓存中 B 的结果,但是已经晚了,形成了一种资源等待死锁现象。
解决办法:调整 A 发送的流程,调用 serviceB 下发和等待响应的逻辑放入新线程中处理,释放 NIO 工作线程资源。
事务嵌套子事务未提交问题
有一个嵌套事务,前提是不希望 serviceB
的数据随着 serviceA
的异常回滚,所以在 serviceB
上添加了Spring 的事务注解,开启新事务。
但是 serviceA
的步骤2依赖插入的数据,而查询操作不会触发 serviceB 上事务的提交,导数数据不一致问题。
这就引发了嵌套事务的提交问题,解决办法,去掉 serviceB
的事务,或者在 serviceB
中用 TransactionTemplate
显式执行事务,可以保证其写入操作及时提交。