最近项目需要使用Java连接到Sql Server多维数据库(Ssas)。在网上找到了一种通过可以通过IIS发布dll来作为jdbc连接串的方法,通过开源的olap4j的jar包,成功实现了类jdbc的方式连接到ssas。但实际应用中往往是通过web服务器的jdbc连接池的方式获得连接。 
        费了九牛二虎之力,终于成功在Tomcat和Websphere下实现了连接池。而当连接池成功创建以后,忽然发现,其实olap4j的数据库连接池和普通的数据库连接池根本没有什么两样,只是一方面受到olap4j官网的几句获得连接代码的影响(使我的方向定位在如何获得olapConnection上,而实际上如果定位在如何获得statement上将更会容易许多),另一方面由于olap4j有些方法没有被实现,使得有些时候报了错误以为就出错了。
一、Websphere下连接Ssas 在Tomcat下使用apache的dbcp的相关jar包的方式,通过dbcp获得OlapCollection
第一种: 
1)JNDI配置

<Context crossContext="true" docBase="D:\lntdc\WebRoot" path="/lntdc" debug="5" reloadable="true">
 <Resource name="jdbc/ssasdb" type="javax.sql.DataSource" factory="org.apache.commons.dbcp.BasicDataSourceFactory" driverClassName="org.olap4j.driver.xmla.XmlaOlap4jDriver" maxActive="25" maxIdle="2" maxWait="5000" username="administrator" password="dcserver" url="jdbc:xmla:Server=http://10.20.14.110/olap/msmdpump.dll;Catalog=olaptest;"/>
</Context>

2)调用方式

BasicDataSource ds=(BasicDataSource)initCtx.lookup("java:comp/env/jdbc/ssasdb"); 
ds.setAccessToUnderlyingConnectionAllowed(true); 
Connection conn = ds.getConnection(); 
ds.setAccessToUnderlyingConnectionAllowed(true);//从ds对象的私有方法中获得对象 
DelegatingConnection connection = (DelegatingConnection) conn; 
OlapWrapper wrapper = (OlapWrapper) connection.getInnermostDelegate(); 
OlapConnection olapConnection = wrapper.unwrap(OlapConnection.class); 
OlapStatement stmt = (OlapStatement)olapConnection.createStatement(); 
CellSet cellSet = stmt.executeOlapQuery(sql);//sql为mdx语句 

上面这段代码还可以用下面这段取代:

BasicDataSource ds=(BasicDataSource)initCtx.lookup("java:comp/env/jdbc/ssasdb"); 
GenericObjectPool pool = new GenericObjectPool(null); 
ConnectionFactory factory = new DataSourceConnectionFactory(ds); 
PoolableConnectionFactory poolableFactory = new PoolableConnectionFactory(factory, pool, null, null, false, true); 
PoolingDataSource poolingDataSource = new PoolingDataSource(pool); 
ds.setAccessToUnderlyingConnectionAllowed(true); 
poolingDataSource.setAccessToUnderlyingConnectionAllowed(true);//与前面一句缺一不可。 
Connection conn = ds.getConnection(); 
System.out.println("Sql Base Connection get Sucessful!"); 
DelegatingConnection connection = (DelegatingConnection) poolingDataSource.getConnection(); 
OlapWrapper wrapper = (OlapWrapper) connection.getInnermostDelegate();

第二种: 1)JNDI配置

<Resource name="jdbc/ssasdb" type="org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS" factory="org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS" driver="org.olap4j.driver.xmla.XmlaOlap4jDriver" maxActive="25" maxIdle="2" maxWait="5000" user="administrator" password="dcserver" url="jdbc:xmla:Server=http://10.20.14.110/olap/msmdpump.dll;Catalog=olaptest;"/>

注意:上面的配置中与一般的tomcat数据源配置不同,user和driver属性,这两个要必需是DriverAdapterCPDS类的属性。

 
<span style="line-height: 1.714285714; font-size: 15px; font-family: 仿宋;">2)调用方式</span> 
DriverAdapterCPDS ds=(DriverAdapterCPDS)initCtx.lookup("java:comp/env/jdbc/ssasdb"); 
Connection conn=ds.getPooledConnection().getConnection(); 
OlapStatement stmt = (OlapStatement)conn.createStatement(); 
CellSet cellSet = stmt.executeOlapQuery(sql);

二、Websphere下连接Ssas
1)jdbc提供程序配置
类路径

olap4j-1.0.0.445.jar
olap4j-tck-1.0.0.445.jar
olap4j-xmla-1.0.0.445.jar
commons-dbcp-1.2.1.jar
commons-pool-1.2.jar
commons-collections.jar

实现类名 org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS
jdbc-provider 
2)jdbc数据源配置 数据库存储器help类名 com.ibm.websphere.rsadapter.GenericDataStoreHelper jdbc-datasource 定制属性:一般是DriverAdapderCPDS类的属性
url:jdbc:xmla:Server=http://10.20.14.110/olap/msmdpump.dll;Catalog=olaptest driver:org.olap4j.driver.xmla.XmlaOlap4jDriver
ds-field
        到此为止,再加上配个jcc 认证(连接olap数据源的用户和密码),就可以测试连接了。 在连接成功时,Websphere会报GenericDataStoreHelper 正在使用的警告,但没发现这种警告对数据库连接有什么影响。 
3)调用方式

 
DataSource ds=(javax.sql.DataSource)initCtx.lookup("jdbc/ssasdb"); 
Connection sc=ds.getConnection(); 
Class clazz=sc.getClass(); 
Method method=clazz.getDeclaredMethod("getJDBCImplObject"); 
method.setAccessible(true); 
Connection oo=(java.sql.Connection)method.invoke(sc); 
OlapStatement stmt = (OlapStatement)oo.createStatement(); 
CellSet cellSet = stmt.executeOlapQuery(sql);//这里使用java的反射机制获得OlapStatement对象。

        在做到这一步之前,我曾经尝试过如何在Websphere中获得OlapCollection的对象,但最终没有成功,其实上面的getJDBCImplObject方法也只能获得ConnectionImpl类的对象,而该类只是个私有类,因此无法获得到该类的实例。
        WebSphere在建立连接池时把ConnectionImpl对象封装在com.ibm.ws.rsadapter.jdbc.WSJdbcConnection类的受保护的属性connImpl中,而该属性是在WSJdbcConnection的构造方法中赋值的,而这个构造方法在class com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource类中被调用,并生成WSJdbcConnection对象。
        我曾经尝试通过如下方式获得OlapCollection的对象,当我获得到dbcp的poolingDataSource时,我以为能够获得到Olapcollection,但最终获得的仍然是WSJdbcConnection的对象(其实想想也该如此):

 
Context context = new javax.naming.InitialContext(); 
DataSource ds = (javax.sql.DataSource)context.lookup("jdbc/ssasdb"); 
GenericObjectPool pool = new GenericObjectPool(null); 
ConnectionFactory factory = new DataSourceConnectionFactory(ds); 
PoolableConnectionFactory poolableFactory = new PoolableConnectionFactory(factory, pool, null, null, false, true); 
PoolingDataSource poolingDataSource = new PoolingDataSource(pool); 
poolingDataSource.setAccessToUnderlyingConnectionAllowed(true); 
DelegatingConnection connection = (DelegatingConnection) poolingDataSource.getConnection();

        Websphere把OlapConnection封装在WSJdbcConnection中(其实tomcat也把它封装在相应的自己实现类中,但可以通过设置factory属性修改这个封装类而已),这种封装将使得获得到这样的类的实例很困难(除非使用java的反射机制),但实际上,在这种机制下,一般的数据库的jdbc的connection并不需要显式地获得到这样的实例,其实WSJdbcConnection的相关数据库执行(增删改查等)方法都是调用被封装的实例的方法,而WSJdbcConnection只是为所有各种类型的数据库查询所提供的统一接口而已,并且WSJdbcConnection这个类也不需要显式地获得,只需要把它强转成Connection的实例即可。
        只是Olap多维数据库的Olap4j驱动程序一般(指官方帮助)使用OlapStatement.excuteOlapQuery方法获得数据,并且获得的数据类型是CellSet,因此我最初认为只有通过这种方式获得OlapConnection,然后OlapStatement,才能获得到结果,因此花费了很大力气去获得OlapConnection,而这种对象被web服务器封装起来了,而且不同服务器的封装变量不同,获得到这样的对象并不容易。
        其实根本没必要获得这样的对象,因为Olap4j与普通的数据库驱动程序其实是一回事,只是我使用了excuteOlapQuery方法而忽略了excuteQuery方法,而如果使用OlapConnection的excuteQuery方法,Olap4j与普通数据库驱动一样,我们不需要显式地获得OlapConnection对象,只需要使用WSJdbcConnection作为java.sql.Connection,然后getStatement,excuteQuery就可以了,只是需要把XmlaOlapStatement里的默认情况下未被实现的方法excuteQuery实现一下即可,只需在这个方法中使用excuteOlapQuery方法获得CellSet,然后把它转换成ResultSet即可。
        其实还是对jdbc的机制(可能也包括Olap4j)不是很了解,导致绕了一个大大的圈子。
注:本文档基于olap4j1.0.445版本编写。

附件
修改后OlapSource.zip ,提取密码:hqlm
olap4j-xmla-1.0.0.445.jar ,提取密码:qnoe
olap4j-1.0.0.445.jar ,提取密码:e388
olap4j-tck-1.0.0.445.jar ,提取密码:6txq

Copyright © 2024 空余恨
Powered by .NET 8.0 on Kubernetes