同样的sql执行结果不同的原因分析 (r4笔记第27天)
今天开发的同事问我一个问题,说有一个sql语句,在weblogic的日志中执行没有结果,但是手动拷贝数据到客户端执行,却能够查到。这种奇怪的问题一下子就能引起我的好奇心,从我知道的原因来看啊,可能是存在不可见字符造成的。
对于不可见字符的问题,有必要先说明一下,可以简单举个例子。
我们创建一个表,然后插入的数据含有不可见字符,比如回车,换行符。
SQL> create table test as select object_id,object_name||chr(10) objname from all_objects where rownum<3;
Table created
插入数据之后,我们查看一下数据。
SQL> select *from test;
OBJECT_ID OBJNAME
---------- -------------------------------
20 ICOL$
46 I_USER1
简单的验证一下,可以看到object_id=46对应的是objname为I_USER1的数据行。
SQL> select *from test where objname='I_USER1';
no rows selected --但是查询的时候却没有任何结果
如果我们在查询中明确的加入那个不可见字符,就可以很容易就插叙出来。
SQL> select *from test where objname='I_USER1'||chr(10);
OBJECT_ID OBJNAME
---------- -------------------------------
46 I_USER1
这个时候可以使用dump函数来分析。
如果可以对比一下数据的dump细节,可以发现唯一的差比是最后有一个chr(10)的字符
SQL> select object_id,dump('I_USER1') DUMP1,dump(objname) DUMP2 from test where objname like 'I_USER%';
OBJECT_ID DUMP1 DUMP2
---------- ---------------------------------- --------------------------------------------------
46 Typ=96 Len=7: 73,95,85,83,69,82,49 Typ=1 Len=8: 73,95,85,83,69,82,49,10
但是当我自信满满的查看了开发提供的日志之后,然后在客户端中又执行了一遍,发现问题似乎比预想的更有些奇怪。
语句是一个简单的select语句,类似select xxxx,xxxxx,xxxx from districute where entity_id=:id and status='ACTIVE', 其中entity_id是传入的参数。
在反复比较之后,基本上这个地方不太可能出现问题,在API想传入这个特殊字符都不容易。但是一模一样的语句在两边执行结果却不相同。
肯定是某个地方出了问题,我静下来,仔细的分析日志中的sql语句,按照目前的情况来说,只可能在某处修改了数据导致的,从这个查询语句往前排查,最终发现了线索。
在这个查询之前,其中有一步是update操作,语句类似update distribute set xxxx=xxx where distribute_no=:distid 从表面上来看,两个语句的唯一共同之处在于都是基于同一个表。
查看sql语句中对应的变量值,发现在select之前的这步操作已经修改了对应的status值,所以在后续的查询中根据entity_id就匹配不到相应的记录了。
通过数据来说明,就如同下面的情况,我们通过distribute_no修改了status值,再通过status,entity_id来匹配对应的数据行得到的结果就为空,在得到的结果为空后,校验失败,于是事务就回退了。然后下一次调用继续update,select,rollack。
entity_id status distribute_no xxxx
100 ACTIVE 100001 xxxxx
分析了这些之后,问题就一下子明朗多了,不是什么特别的bug,不是什么特别的场景,都是潜意识中自己被误导了。所以大家在排查问题的时候,可能提供给你的信息不是最全面最完整的,我们需要分析去佐证。
- Sublime text 3 中Package Control 的安装与使用方法
- 用functools.lru_cache实现Python的Memoization
- 腾讯互联网与社会研究院秘书长司晓:将联合开展研究合作
- 幻灯片jQuery插件Orbit 介绍(附添加到WordPress教程)
- Gravatar开发者手册
- Gravatar开发者手册
- 使用Google CDN服务提供的jQuery库
- 比特币的分叉币都认为能够取代比特币,事实真的是这样吗?
- Google官方网页载入速度检测工具PageSpeed Insights 使用教程
- ASP.NET 路由
- Kafka定时清除过期数据
- 腾讯高级副总裁郭凯天:打造腾讯智库分析互联网产业前沿问题
- Google Chrome 浏览器 开发者工具 使用教程
- 反向代理(Reverse Proxy)及 IIS 7 应用请求路由模块
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法