最近項目需要使用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
2)jdbc數據源配置 數據庫存儲器help類名 com.ibm.websphere.rsadapter.GenericDataStoreHelper
定制屬性:一般是DriverAdapderCPDS類的屬性
url:jdbc:xmla:Server=http://10.20.14.110/olap/msmdpump.dll;Catalog=olaptest driver:org.olap4j.driver.xmla.XmlaOlap4jDriver
到此為止,再加上配個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