按照之前一篇博客的方法,配置了Amoeba链接Oracle的集群。在使用过程中遇到了一个问题:Amoeba对外使用的是mysql协议,所以通过Amoeba查询的时候也得使用mysql的SQL语法。Oracle和mysql语法在很多地方还是不一样的,比如今天遇到的问题,Oracle的外链接符号(+)mysql就不认识。今天摸索了半天,找到一个解决办法,虽然不是很完美的方法,不过也能解决问题。
首先我们看看如果在Amoeba里用(+)会怎么样。我们先建两个表用于实验,一个STAFF,只有两列ID和NAME;另一个表INFO,两列ID和AGE,两个表通过ID可以链接。然后再往两个表里随便插一些数据。之后用mysql客户端连接上Amoeba。如果我们查询这个SQL:
SELECT STAFF.ID, STAFF.NAME FROM STAFF, INFO WHERE STAFF.ID=INFO.ID
返回的结果是正确的,结果是从各个DB返回的结果再合并一起的结果。然后,我们查询这个SQL:
SELECT STAFF.ID, STAFF.NAME FROM STAFF, INFO WHERE STAFF.ID=INFO.ID(+)
返回的结果就不对了,看上去只是其中一个DB的结果,而且就是amoeba.xml里defaultPool里配置的那个数据库。
如果我们再看看logs目录下的project.log文件,发现我们查询了上述SQL后Amoeba报出的异常,异常信息就是SQL parse错误。
所以我们大概能猜出是怎么回事:Amoeba试图解析SQL的时候出错了,所以就跳过了我们配置的rule,直接把SQL原封不动地仍给配置的defaultPool。问题是,在amoeba.xml的defaultPool中是只能配置一个pool的,如果能配置多个pool的话,问题就解决了。
经过一番探索,我想出一个办法:改代码。Google Code上下载Amoeba的代码:http://code.google.com/p/amoeba/source/checkout 。我checkout的是trunk.2.0.1,不知道最新版本会不会有什么问题。在amoeba工程里找到com.meidusa.amoeba.route.AbstractQueryRouter类,大概在470行左右的地方,找到:
public void init() throws InitialisationException {
defaultPools = new ObjectPool[] { ProxyRuntimeContext.getInstance().getPoolMap().get(defaultPool) };
//......
}
我们欣喜地发现,虽然配置文件里defaultPool只有一个pool,但是在程序里面实际上是先从一个pool的名字,生成一个pool的数组defaultPools。所以我们只要在defaultPool里写多个pool的名字,然后在这个自己解析一下,把多个pool塞进defaultPools里就行了。我们把这段代码改成这样:
private ObjectPool[] getDefaultPools() {
String[] defaultPoolStrs = defaultPool.trim().split("[\\,\\s]+");
int size = defaultPoolStrs.length;
ObjectPool[] pools = new ObjectPool[size];
for(int i=0; i<size; i++) {
pools[i] = ProxyRuntimeContext.getInstance().getPoolMap().get(defaultPoolStrs[i]);
}
return pools;
}
public void init() throws InitialisationException {
defaultPools = getDefaultPools();
//.....
}
之后在trunk根目录下执行ant编译,在dist/lib下找到编译出来的amoeba-2.0.1-BETA.jar,放在amoeba服务器中amoeba目录下的lib里面。然后在amoeba.xml里,把defaultPool配置成:
<defaultPool>server1,server2,server3</defaultPool>
重新启动Amoeba,再查询带有(+)的SQL,结果就正确了。
这个办法并不是个完美的方法,因为这样查询之后在project.log里面还是有异常信息的。
最正确的方法应该是修改在amoeba-aladdin工程下com.meidusa.amoeba.aladdin.parser.sql包里的AladdinParser类(这个类应该是从AladdinParser.jj文件自动生成的)。具体做法还要以后在研究研究。