项目日记 - 疑难杂症

不知不觉工作已经有三年了,期间学到了很多东西,也经历过喜怒哀乐,回想一下,已经记不了多少了。决定还是把记得的写下来。
[b]
[size=large]1. 数据的读取[/b][/size]

[b]问题[/b]:我们有个独立的程序来处理系统的数据变化并产生Version信息,在Version中会记录对象的主键的值并以一定的格式拼接在一起,但是拼接的方式没有相关的元数据定义。在Version显示的一端则根据既有数据的格式总结出了规律进行解析和显示。而对于哪些数据需要产生Version,我们用了一张表来定义并且可以精确到列。这样在产生Version的时候我们取出这些列并得到正在处理的记录上的值来生成Key。 问题是突然有一天我们发现这些Key的格式发生了改变,在程序里无法进行解析了。

[b]解决方案[/b]:
Step 1: 我们检查了这个产生Version的独立程序(别人开发我们在维护),发现没有任何的代码改动。

Step 2: 既然没有改动,我们接着查询了所有的Version信息,看以前是不是也出现了这种乱序的问题,但是除了近期没有这样的数据产生。

于是,问题开始变的诡异了!

Step 3: 我们开始怀疑定义哪些数据可以产生Version的那张表,称为A。因为产生Version时,是读取这些列名,然后再拼装它们的数据,所以猜测是读取这些列的时候顺序变了。

Step 4: 找出一个很老的数据库,同样的SQL跑了一遍,果然结果顺序跟现在的DB上不一样了。

Step 5: 我们想到了如果没有指定Order By,那么数据是按照它们的插入顺序返回,但是我们没有指定Order By,也没有动过这些数据。

于是, 问题又开始诡异起来了!!

Step 6: 开始思考什么操作会改变数据的顺序,突然想起来表重组时可以附加索引,如REORG TABLE XXXX USE INDEX XXXX。会不会是表的数据要根据INDEX的顺序进行重排以保证比较高的聚簇因子。

Step 7: 联系数据库的Admin,果然最近每周一次会进行一些表的重组工作。于是准备重新插入这些数据以保证他们的读取顺序不变。经历了几次尝试,终于成功了。看到这个表一直都是被单独查询而且总共就一百多条记录,还是去掉索引比较安全。

[size=large][b]2. 数据库触发器[/b][/size]

[b]问题[/b]:在业务流程上需要一个数据从draft到publish的过程,在数据库上的做法就是使用不同的Schema来维护draft的隐蔽性,当需要publish的时候通过表上的触发器来把数据搬到目标Schema。这个表上有20个触发器,10个是用来更新数据的,10个用来插入新的数据,正确的顺序先插入新的数据,然后更新所有数据的标志位。 但是某一天,新的数据总是插不进来了,而且Log里没有报错。

[b]解决方案[/b]:

Step 1: 检查了正确的数据(用户报告的)在源Schema有没有产生,结果是确实有这样的数据。

Step 2: 检查Trigger的状态是不是Valid, 通过SELECT VALID FROM SYSCAT.TRIGGERS WHERE TABSCHEMA=' ' AND TABNAME=' '; ,结果都是VALID的

于是,问题开始变得诡异了!

Step 3: 想到数据应该是没有按照设定的顺序进行处理,导致Insert的操作没有查询的数据来插入,就猜到是Trigger的执行顺序乱了。

Step 4: 问题是Trigger按照什么顺序执行呢? 猜测是根据创建时间。 二话不说,做实验。 先查看Trigger的定义,SELECT CREATETIME FROM SYSCAT.TRIGGERS WHERE XXXXX, 发现按照时间来排的,顺序是不正确的。于是DROP掉这些Trigger,然后按照指定顺序重建,再试,OK了。
[size=large][b]
3. HTTP GET[/b][/size]

[b]问题[/b]:项目中使用了Prototype这个库,并采用了它的AJAX框架,在响应函数中,我们会检查它的Response code来检查请求处理的结果。有些时候,我们发现这个响应code为空值,而且连接畅通(连接的本机Jetty服务器)。

[b]解决方案[/b]:
Step 1:我们知道只要连接畅通,HTTP的status code不可能是一个空值。只能说明连接没有发出去。

Step 2:因为服务器在本机,而且其他的请求都可以正常响应,那么连接发不出去就比较诡异了。细细想想,在什么情况下浏览器会不发连接出来呢? 并发连接数超过HTTP限制?违反HTTP协议的请求?

Step 3: 考虑到页面上没有使用轮询的消息机制,不会有同时两个以上的连接在运行,那么就把焦点放在了请求是否违背了HTTP协议。审视了项目的AJAX框架,发现比较多的AJAX请求是通过GET方式发出来的,而且这些GET的参数是在后端生成好的,比如:
remoteCall('index.jsp?_P=');
其中有可能包括了对象的序列化数据。

Step 4: 问题已经很明朗了,GET的请求参数大小是受限的,而对象的序列化会跟着对象的复杂程度正比例变化,应该是GET的大小超过了限制,浏览器就不会发出这样的请求了。检查AJAX的调用参数,改之,问题解决了,:)

[size=large][b]4. 数据库隔离级别[/b][/size]

[b]问题[/b]:项目中为了分配主键的ID,使用了UR的隔离级别来允许脏读。 于是大家都跟风的去在自己的SQL中加入UR来提高速度。 当我们有一个独立程序用于导出数据时,在一个导出过程中读取了事务的部分数据。

[b]解决方案[/b]:
在独立程序中使用CS的隔离级别。

    推荐阅读