那些年,我们见过的 Java 服务端“问题”
常见系统间交互方式
请求-应答

适用范围:
适合于简单的耗时较短的接口同步调用场景,比如 Dubbo 接口同步调用。
通知-确认

适用范围:
适合于简单的异步消息通知场景,比如 MetaQ 消息通知。
请求-应答-查询-返回

适用范围:
适合于复杂的耗时较长的接口同步调用场景,比如提交作业任务并定期查询任务结果。
请求-应答-回调

适用范围:
适合于复杂的耗时较长的接口同步调用和异步回调相结合的场景,比如支付宝的订单支付。
请求-应答-通知-确认

适用范围:
适合于复杂的耗时较长的接口同步调用和异步消息通知相结合的场景,比如提交作业任务并等待完成消息通知。
通知-确认-通知-确认

适用范围:
适合于复杂的耗时较长的异步消息通知场景。
数据查询不分页
在数据查询时,由于未能对未来数据量做出正确的预估,很多情况下都没有考虑数据的分页查询。
普通查询案例
以下是查询过期订单的代码:
/** 订单DAO接口 */
public interface OrderDAO {
/** 查询过期订单函数 */
@Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day)")
public List<OrderDO> queryTimeout();
}
/** 订单服务接口 */
public interface OrderService {
/** 查询过期订单函数 */
public List<OrderVO> queryTimeout();
}
当过期订单数量很少时,以上代码不会有任何问题。但是,当过期订单数量达到几十万上千万时,以上代码就会出现以下问题:
- 数据量太大,导致服务端的内存溢出;
- 数据量太大,导致查询接口超时、返回数据超时等;
- 数据量太大,导致客户端的内存溢出。
所以,在数据查询时,特别是不能预估数据量的大小时,需要考虑数据的分页查询。这里,主要介绍”设置最大数量”和”采用分页查询”两种方式。
设置最大数量
“设置最大数量”是一种最简单的分页查询,相当于只返回第一页数据。例子代码如下:
/** 订单DAO接口 */
public interface OrderDAO {
/** 查询过期订单函数 */
@Select("select * from t_order where status = 5 and gmt_create < date_sub(current_timestamp, interval 30 day) limit 0, #{maxCount}")
public List<OrderDO> queryTimeout(@Param("maxCount") Integer maxCount);
}
/** 订单服务接口 */
public interface OrderService {
/** 查询过期订单函数 */
public List<OrderVO> queryTimeout(Integer maxCount);
}
适用于没有分页需求、但又担心数据过多导致内存溢出、数据量过大的查询。
