跳至主要内容

捉虫记 (一)

最近在维护几个上线的产品时遇到的几个 bug 都蛮有意思的,记录下来供参考。 第一个问题是在使用 JPA Repository 的时候产生的。业务逻辑很简单,接受一个 `List` 作为 `eventIds`,针对每个事件找到相应的 subscriber 然后发送一封邮件。 原本的实现是用 Java 8 的 lambda 来完成的, `eventIds.stream().forEach(...)` 在其中调用 Spring Data `JpaRepository.findOne()` 方法。后来被重构过变成了先调用 `JpaRepository.findAll()` 来取得 Entity,再用 Java 8 Stream 的方法来处理。 这个修改乍一看挺好的——假定需要处理 50 个 events,原本的实现会至少查询 50 次数据库,而后者只要一个调用就搞定。但是后来在测试中发现如果传入的数据集合超过 1000 个元素,就无法完成请求。后台的 error log 中显示的是 Oracle 的一场 —— `IN` expression 无法处理超过 1000 个表达式! Oracle Database 经常会给出莫名的 error message,以后有机会慢慢说。不过这个案例中倒是没啥可以批评 Oracle 的,因为的确是 JPA 执行数据库查询的时候引发的问题。 第二个问题是由 `Lob` 引起的。在定义 Entity 的时候,如果原本的 column 是 BLOB 或是 CLOB 类型的数据字段,对应的 Java Class 内需要用 `@Lob` annotation 加以标记。否则会导致不稳定的查询错误,而且这个错误信息很让人困惑…… 为了重现问题尝试了 N 次,有台服务器基本无法重现,而另一台服务器倒是有 1/3 的概率可以重现。 第三个问题是由 JSON 引起的,在上线的产品中大量使用 JSON 从 Server 端返回数据,而 Client (Web) 使用了 AngularJS 这样的框架来执行数据的解析和绑定。在一个新发布的 release 中客户抱怨说之前保存过的数据现在显示不出来了(这是简化版,客户只是抱怨说某些页面上数据缺失,QA无法重现问题,只能靠俺们分析之后得到的结论)。 在处理 form 的时候,Client 以 JSON 形态提交表单,由于是 application draft 所以 Server 端没有做额外的处理就直接保存了 Draft 到 Database。可是由于这个 release 有个 bug fix 修改了 Java Class 的结构(添加了额外的 properties),而这个新增 property 没有保存在 draft 中,于是新上线的产品在读取之前保存的 draft 之后就找不到相应的 property。本质上这个就是 DTO version hell……

评论