Wednesday, April 29, 2009

解决字符编码问题

字符编码集的问题

这两天和一个第三方平台进行联调,碰到一个字符编码的问题,经过自己的分析并与对方进行沟通,最终问题得到妥善 解决。字符编码让人非常恼火,只有真正理解了其中的机制之后才能快速的找出问题的根源。 幸亏去年读过好些关于字符编码的文章,让我对这个问题有很清晰的认识,这也是这次能快速解决问题的根本。
记录一下解决这个问题时我的分析过程,也反省一下还有些什么可以提高的。
问题背景: 与对方平台的接口采用HTTP POST方式传递XML报文方式交换数据,其中报文体BODY是以DES加密的字符串。由于项目需求,在加密前进行了一次字符串转换,将字符串的byte[]转成Hex字符再进行DES。

问题现象:在公司测试环境上,发现对方传递过来的报文能正确解析出XML结构并正常处理,但是查看最终生成的数据中发现其中的中文为乱码。但是另外有个发现是我在生产测试机上在终端看到了正确的中文字符。

问 题分析解决过程:由于报文解析正常,业务处理也正常,存在中文出现乱码问题,因此我认定是自己内部处理出现错误。由于内部处理过程中也存在两个不同服务的 交互,于是先是假定问题出在两个服务传递数据时的问题(当时对于这个猜测,我并没找到充足的理论依据,事实证明这种猜想是错误的),于是debug接收数 据的服务。Debug中发现接收到的数据已经是乱码(值全部为 65533)。 问过做内部两个服务数据交互接口的开发人员,他说是通过Socket传递数据的,不可能存在编码问题,因此把我问题定位在解析这个过程上。于是针对解析部 分进行Debug,发现DES解密出现的串中,中文已经是乱码 (值全部为65533)。 于是查看解密的代码,在查看解码代码时发现了问题,正是解决该字符集问题的关键!在这里要提一下,幸亏对方给了我们解密与加密的实现代码,否则这问题更难 定位。代码中在将一个String转换成byte[]时采用str.getBytes()方法,该方法采用JVM默认的编码将一个String转换成 byte[]。这时让我想起之前在HP-UX终端打印的看到正确的中文,而在公司测试环境下的Linux下面却是乱码的。我断定是乱码的问题是由于对方加 密时JVM的编码与我们测试系统中解密时采用的编码方式不一致造成的。由于对方工作人员已经下班,没办法直接问他们的字符编码方式。但是想到HP-UX能 正常解析,只要找到HP-UX上JVM启动时设置的编码就能知道问题原因了。但是该死的HP-UX并没有像Linux那样的/porc文件系统来记录进程 信息,而且ps 命令只能显示很少的命令行字符,折腾了半天也没能看清楚cmdline的全貌。这时想起在Linux下面启动时应该和HP-UX下JVM启动参数设置是一 致的, 于是查看Linux下的cmdline。 但是发现JVM启动时并没有指定file.encoding参数,这表明JVM采用操作系统默认字符集了。 查看后发现Linux下是C,HP-UX不熟悉,折腾半天也没搞明白,自己找到编码方式的尝试失败。于是决定等第二天直接问对方采用的字符编码方式。
第二天早上和对方开发人员沟通后,对方告诉我他们是采用GBK编码。 我马上在JVM启动时加上一个启动参数-Dfile.encoding=GBK,再次发送报文测试,新生成的数据中中文不再是乱码,问题终于解决了。

问题的反思:
问题解决了,但是对于问题解决过程的反思更重要。
解决方案中可能引入的新问题是JVM改成GBK编码会不会对该服务中其它部分产生影响?
再 回顾这个问题,罪魁祸首就是用了String的getBytes()方法,或许在使用该方法时应该显示指明其编码类型?所有代码都在单个JVM中运行或许 不需要关心这 个问题,因为编码总是统一的。但是在多个JVM中,并且JVM之间要交换数据,使用这个方法时或许就需要注意一下了。
再回顾问题解 决过程,发现在分析问题过程中还有许多可以改进的地方。 比如开始就就忽略的HP-UX上面编码是正确的这个关键点,而是在折腾了半天之后,定位到是JVM编码问题时才想起这个关键点。从HP-UX与Linux 上出现不同的解密不同时就可以判定在JVM启动时没有指定默认字符集,而不需要花费很多时间去找到进程启动的cmdline. 这些都是在经过清晰,严谨的思考,只要再往前一步就能推断出答案的,而在解决问题中却没有发现。 遇到问题保持头脑清醒,周密,严谨的思考比想到一半就开始实践更有效率。这些都是今后工作中需要提高的。

Monday, April 27, 2009

Something about Database Design

I read some articles about how to design a relation database. There is a note extract from the articles. it is a good guide to design a database.

Normalisation is the term used to describe how you break a file down into tables to create a database.
The targets of normalization:
1.minimization of data redundancy
2.minimization of data restructuring
3.minimization of I/O by reduction of transaction sizes
4.enforcement of referential integrity

The First Normal Form (1NF) addresses the structure of an isolated table.
The Second (2NF), Third (3NF), and Boyce-Codd (BCNF) Normal Forms address one-to-one and one-to-many relationships.
The Fourth (4NF) and Fifth (5NF) Normal Forms deal with many-to-many relationships.

Normal Form define:
A table is said to be in First Normal Form (1NF), if all entries in it are scalar-valued. Relational database tables are 1NF by construction since vector-valued entries are forbidden.
A table is in Second Normal Form (2NF) if every non-key field is a fact about the entire key. In other words, a table is 2NF if it is 1NF and all non-key attributes are functionally dependent on the entire primary key (that is, the dependency is irreducible).
A relation is in Third Normal Form (3NF) if it is 2NF and none of its attributes is a fact about another non-key field. In other words, no non-key field functionally depends on any other non-key field.

Every field in a record must depend on The Key (1NF), the Whole Key (2NF), and Nothing But The Key (3NF).

Some tips:
1.Table name all caps.
2.An attribute is a descriptive or quantitative characteristic of an entity. Initial Cap.
3.PK is a uniquely identify each instance of an entity,should not change. The Integer datatype is more effecient than CHAR datatype.
should non-intelligent.
4.A relationship is a logical link between entities. one-to-many we can use FK to implements.
5.many-to-many relationship may be resolved by creating an intermediate entity known as a cross-reference(XREF) entity.
6.FK, the value is dependency on pk.
7.identifying or non-identifying.
8.Cardinality "How many instances of the child entity relate to each instance of the parent entity?"

the process of design a database.
Table define
Attribute define
Relationship define

All the things are picked up from the articles which refered in this post:10-useful-articles-about-database.

Saturday, April 11, 2009

Thought about Program Language

I have read an article which talks about the program language.It impressed me so much. The author told a story about he has written a startup by Lisp,and explained why people say Lisp is the most powerful language. He said: the programming languages are not just technology,but what programmers think in.They are half technology and half religion. I really agree with her.

Programming language affect you thinking. When you have a problem,naturally you want to solve by you familiar language. Sometime it isn't the optima,even it's the worst solution. Each language have some good features. I'm familiar with java.So when I have a problem, spontaneous thinking is try to find a solution with java style. Because I don't familiar with other language, so I can't find another way to deal with the problem. It's my dead spot. But when I learned a little Shell, I can get thing done with Shell. Sometimes it's more simple and compact than with java. It give me an chance to think problem from other side. it's very valuable. In this lesson, I learned that the more you know,the wider you can think. The Lisp have more powerful feature than others. If you are skilled in Lisp you know more tips than you can get from other languages.

But wait a minute. Sometime the knowledge isn't good for you thinking. There is a saying:if all you have is a hammer, everything looks like a nail. The familiar language( or knowledge) can affect you thought,sometimes it bring you to the wrong road. You have a problem,you want to use you knowledge to solve it. You just want to solve the problem with familiar knowledge,even make people don't thing the essential of the problem. But we must have some knowledge to get things done. How to avoid this thinking dead spot? I think it would be Critical Thinking.When we learning a language or things, we should ask some questions:what it's advantage,what it's disadvantage,what things it hold good for, what things it isn't applicable. If we know that, we can do the right things with right tools.

Friday, April 3, 2009

一个批量下载文件的脚本

最近在重新学习英语发音,李笑来老师的博客上提供了很多相关方面的资料。 其中有些页面有很多单词发音的wav音频文件,但是我的浏览器无法播放这些音频文件。于是准备把他下载下来,但是呢一个一个地下载实在是太慢了,而且也感觉比较笨。 于是自然想到写一个脚本来干这件事情。
先去看了一下包含有音频文件的HTML页面的源码,音频文件的行非常有规律。
对于这样的文件使用Shell非常容易处理。 下面就是我写的一个简单的脚本:
#!/bin/bash
wget $1 -O wav.html
egrep ".wav\>" wav.html | awk -F '"' '{print $2}' > wav.list
wget -i wav.list

怎么使用呢?只要这样就行:

star@star-desktop:~/Documents/English/pronounce/words$ ./getWav.sh http://www.xiaolai.net/index.php/archives/4047.html

其实还可以再改一改,比如把下载文件名也改成通过参数传递进去。 不过这个已经够我用了。
一转眼功夫就下载完了所有文件,实在是高效啊。
Linux下通过Shell脚本高效地完成一些繁琐的事情实在是太酷了。

Thursday, March 19, 2009

Ubuntu 8.10安装Oracle 10g笔记

上周末重新换了一块硬盘,因此操作系统和数据库都要重装一遍。重新安装Oracle 10g的过程中遇到不少有趣的问题,在解决这些问题的过程中学到了不少东西。
安装过程主要是参照孙高勇的那份文档来做的,但是在Ubuntu 8.10上面还会遇到一些其它问题。
1、关于安装是OUI中文的问题
该问题困扰我很久,一直没找到解决办法,最终采用英文环境进行安装以避免安装过程中的中文乱码问题。

2、安装过程运行runInstaller过程中会出现unzip的错误
该问题是由于Oracle 10g安装文件中/install 下的unzip与Ubuntu 8.10自带的unzip版本不一致导致的,我的解决方法如下:
install$ mv unzip unzipbak
install$ ln -s /usr/bin/unzip unzip

3、运行runInstaller后出现如下报错:
Error in writing to directory /tmp/OraInstall2009-03-16_02-26-36PM. Please
ensure that this directory is writable and has at least 60 MB of disk space.

该问题通过修改/install下所有文件的权限得于解决

在解决安装过程出现的问题时,发现了自己现在有一个很不好的习惯:在出现问题是首先想到的不是分析问题并尝试解决,而是通过Google找答案。
查了一下google的web history,发现只要在上网,每天都用使用Google进行搜索。在这过程中很多问题或许能找到答案,但是对于问题的理解并不深刻,下次出现该问题仍然无法解决。
在解决第二个问题过程中,我在Google没有发现任何有效信息,最终还是自己静下心来分析出错的日志,最终确认是由于unzip的版本冲突导致该问题。
在这过程中给我印象非常深刻,很多的问题在分析日志的过程中肯定能找到线索, 这在使用Ubuntu的过程中非常重要。

Wednesday, March 18, 2009

Java程序运行时,各变量在JVM中存放的位置

Java程序运行时,各变量在JVM中存放的位置

JVM对于内存是通过分成不同的部分来管理的,主要包括方法区(Method Area),堆(Heap),Java栈(Stack)。其中方法区存放装载到JVM中的类的信息,堆存放类的实例对象,Java棧以帧为单位保存线程运行的状态,存放每一个线程在程序执行过程中需要的数据信息。
对应于Java文件中的各种类变量,实例变量,类本身等内容,下面阐述一下它们在JVM中的存放位置。
public static final int i =1;
这个i在编译时就可以确认它的值,因此它作为一个常量被直接写在.class文件中,其它类用到这个i的时候,在编译过程中会拷贝i的值到该类的.class文件中。
public static final int i = (int)(Math.random() * 4);
如果是以上面这种形式的定义变量,因为其在编译时无法确认其值,在运行过程中才会确定值,因此它会当作一个类变量在类初始化是存放在方法区中。

static int i = 9;
以上这种形式定义的变量在类初始化时被初始化正确的值,并将其与类信息一起存放在方法区。

int i = 9;
这种形式定义的变量是实例变量,在类被实例化时赋于正确的初始值,和类实例对象一起存放在堆区。

void getXX(int a){
int i = 1;
}
上面这种形式定义的变量a是一个参数,i是一个局部变量,只在运算过程在有效,因此会存放在Java棧中棧帧中,在方法返回后其值也会无效,等待GC回收。


通过上面的论述可以推断出有哪些情况可能会导致OutOfMemory的错误了。
1、过多的类信息被装载到方法区,导致该区域OutOfMemory错误,在一些框架中通过反射机制生成大量的类信息可能导致该问题。
2、使用过多的static类型的类变量,特别是将大的数组,字符串等,导致方法区占用内存过多,造成OutOfMemory错误。由于JVM中并没有提供设置方法区大小的参数,因此只能通过加大JVM的内存来解决。
3、程序创建了过多的线程,导致Java棧使用内存过多,导致OutOfMemory。可通过-Xss来设置每一个Java thread stack 的大小来解决该问题。
4、程序生成了过多的实例对象,使得堆占用大量内存,最终出现OutOfMemory错误。 该问题可通过设置下面两个JVM启动参数来避免:
-Xms set initial Java heap size
-Xmx set maximum Java heap size

Tuesday, March 10, 2009

expect小记

今天在找资料时意外地学到了如何在Shell中进行交互。 学习资源在这里
下面是我写的一个在Terminal里通过bash操作SQLPlus的脚本。
#!/usr/bin/expect

spawn sqlplus

expect "name"

send "umail\r"

expect "password\r"

send "umail\r"

expect "SQL>"

send "desc employees\r"

expect "SQL>"

send "quit\r"
上面的几个指令的意义如下:
pawn命令激活一个Unix程序来进行交互式的运行。 
send命令向进程发送字符串。
expect命令等待进程的某些字符串。 
expect支持正规表达式并能同时等待多个字符串,并对每一个字符串执行不同的操作

这个东西非常有用,可以直接将SSH,FTP等写到脚本里面,不需要人工来干预它。在系统维护中可以写一些脚本处理某些批量处理的问题,而不需要有人来看着它。
更多内容请看这里