前些日子,农总行的客户有个需求,需要跨Sybase ASE和Sybase IQ两个数据库操作,并且保证事务的完整性,而且客户不希望通过数据库层来保证事务,只希望在代码层控制。
这样的需求可能第一反应就是采用JTA,及XA事务(及通常所说的两阶段提交)支持。但是,这其中有一个数据库Sybase IQ,这是一个“数据仓库型”的数据库。Sybase中国区的技术支持也不能肯定是否IQ支持XA事务,因为IQ跨数据库事务操作在国内还没有过。
于是,只得做了个技术预研。说真的,虽然搞了这么多年java,还真没有碰到过跨数据库事务的项目,这次机会难得,好好研究一把。
本机暂时没有Sybase ASE,只能拿SQLServer替代一下。测试环境如下:
JTA Server: Jboss4.0.4
DataBase One: MS SQLServer 2000
DataBase Two:Sybase IQ 12.6
OS: Windows2003
JDBC Driver for sqlserver: jTDS1.2
JDBC Driver for Sybase IQ: jConnect-6_05
首先在Jboss中配置XADataSource。在 jboss404\docs\examples\jca 目录下,只有mssql-xa-ds.xml和 sybase-ds.xml,没有sybase-xa-ds.xml样例。于是自己写了一个sybase-xa-ds.xml。—— 后来发现这是“错误的做法”,只使用sybase-ds.xml即可了。
mssql-xa-ds.xml内容如下:
<datasources>
<xa-datasource>
<jndi-name>MSSQLXADS</jndi-name>
<track-connection-by-tx/>
<isSameRM-override-value>false</isSameRM-override-value>
<xa-datasource-class>net.sourceforge.jtds.jdbcx.JtdsDataSource</xa-datasource-class>
<xa-datasource-propertyname="ServerName">localhost</xa-datasource-property>
<xa-datasource-propertyname="DatabaseName">foxtest</xa-datasource-property>
<user-name>sa</user-name>
<password>sa</password>
<metadata>
<type-mapping>MSSQLSERVER2000</type-mapping>
</metadata>
</xa-datasource>
</datasources>
sybase-xa-ds.xml内容如下:
<datasources>
<xa-datasource>
<jndi-name>XASybaseDS</jndi-name>
<track-connection-by-tx/>
<isSameRM-override-value>false</isSameRM-override-value>
<xa-datasource-class>com.sybase.jdbc3.jdbc.SybDataSource</xa-datasource-class>
<xa-datasource-propertyname="ServerName">localhost</xa-datasource-property>
<xa-datasource-propertyname="User">dba</xa-datasource-property>
<xa-datasource-propertyname="Password">sql</xa-datasource-property>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.SybaseExceptionSorter
</exception-sorter-class-name>
<no-tx-separate-pools/>
<metadata>
<type-mapping>Sybase</type-mapping>
</metadata>
</xa-datasource>
</datasources>
专门写了一个TestCase,准备同外围访问通过remote jndi方式访问datasource。
Hashtableevn=newHashtable();
evn.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
evn.put(Context.PROVIDER_URL,"jnp://localhost:1299/");
InitialContextjndiContext=newInitialContext(evn);
DataSourceds=(DataSource)jndiContext.lookup("java:MSSQLXADS");
但是怎么连都访问不通:
而且jboss启动时候,datasource部署的信息也是:
13:34:31,473 INFO[WrapperDataSourceService]
Bound ConnectionManager 'jboss.jca:name=MSSQLXADS,service=DataSourceBinding'
to JNDI name 'java:MSSQLXADS'
后来在jboss wiki(http://wiki.jboss.org/wiki/Wiki.jsp?page=ConfigDataSources)上发现了问题所在:<use-java-context> - A boolean indicating if the jndi-name should be prefixed with java: which causes the DataSource to only be accessible from within the jboss server vm. The default is true..
于是在ds.xml配置文件中增加了 <use-java-context>false</use-java-context> 属性,才算能够访问到jndi对象,只是 jndiContext.lookup("java:MSSQLXADS"); 需要更改为 jndiContext.lookup("MSSQLXADS")。
但是,在执行到DataSource ds = (DataSource)jndiContext.lookup("MSSQLXADS");这一步的时候,就抛出了ClassCastException,跟踪发现这个问原来是jndiContext.lookup返回的是javax.naming.Reference对象。
查了查资料,才发现这个问题的根源是由于javax.sql.DataSource不是可序列化,所以不能够在通过JNDI远程访问:The datasource unlike EJBs, does not implement a remote interface. (Notice the returned object is a javax.naming.Reference rather than DataSource). Hence if you want to lookup datasource, you have to be in the same process.
这个问题详细可参考:
没有办法,之后转移到Jboss Server内部来测试,不通过TestCase远程JNDI访问测试了。
内部通过一个Servlet测试,代码主体如下:
publicvoidinit()throwsServletException{
UserTransactionutx=null;
try{
InitialContextjndiContext=newInitialContext();
utx=(javax.transaction.UserTransaction)jndiContext.lookup("UserTransaction");
utx.begin();
insertSQL_();
insertSybase();
utx.commit();
}catch(Exceptione){
if(utx!=null){
utx.rollback();//此处异常代码省略
}
}
}
privatevoidinsertSQL_()throwsException{
Connectionconn1=createXAConnection("MSSQLXADS");
insertData(conn1);//插入数据测试,代码省略
}
privatevoidinsertSybase()throwsException{
Connectionconn2=createXAConnection("XASybaseDS");
insertDataSybase(conn2);//插入数据测试,代码省略
thrownewException("");//此处做异常回滚测试
}
privateConnectioncreateXAConnection(Stringjndiname)throwsException{
InitialContextjndiContext;
try{
jndiContext=newInitialContext();
DataSourceds=(DataSource)jndiContext.lookup(jndiname);
returnds.getConnection();
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
returnnull;
}
但是程序在执行到获取Sybase JNDI DataSource的时候总是出现ClassCastException,错误如下:
16:26:14,605 WARN[JBossManagedConnectionPool] Throwable while attempting to get a new connection: null
org.jboss.resource.JBossResourceException:
Could not create connection; - nested throwable: (java.lang.ClassCastException)
at org.jboss.resource.adapter.jdbc.xa.XAManagedConnectionFactory.
createManagedConnection(XAManagedConnectionFactory.java:162)
at org.jboss.resource.connectionmanager.InternalManagedConnectionPool.
createConnectionEventListener(InternalManagedConnectionPool.java:539)
at org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.
allocateConnection(BaseConnectionManager2.java:812)
at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:88)
这个错误耽误很长时间,后来突然发现,Sybase的jConnect驱动,竟然没有实现javax.sql.XADataSource的接口。
于是,搜索了一下是否还有其他商业驱动支持Sybase IQ,但发现只有Sybase自身的jConnect。
到这里好像Sybase IQ不支持XA,但是随后做了一个大胆的测试,就是对Sybase使用sybase-ds.xml,而对SQLServer依然采用mssql-xa-ds.xml。sybase-ds.xml配置如下:
<datasources>
<local-tx-datasource>
<jndi-name>jdbc/SybaseDB</jndi-name>
<connection-url>jdbc:sybase:Tds:localhost:2638</connection-url>
<driver-class>com.sybase.jdbc3.jdbc.SybDataSource</driver-class>
<user-name>dba</user-name>
<password>sql</password>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.SybaseExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>Sybase</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
这个测试后,竟然发现此种配置竟然也支持JTA。
虽然这个实验可以控制Sybase IQ在JTA中的事务,但是到目前为止,我还是不太情况Sybase jConnect没有支持XADataSource接口,如何能够在JTA事务中控制的。
后来又做了进一步的测试,把MSSqlServer的那个数据源也换成了mssql-ds.xml,也是没有使用XA那个,竟然发现也受JTA的事务完整性控制。
目前这个还是有些疑问,有待再仔细查阅资料,如果有明理者,也请告知一二。
分享到:
相关推荐
NULL 博文链接:https://aga.iteye.com/blog/298106
JBOSS使用指南JBOSS使用指南JBOSS使用指南JBOSS使用指南JBOSS使用指南JBOSS使用指南JBOSS使用指南JBOSS使用指南
NULL 博文链接:https://xnbhnly.iteye.com/blog/1547459
jboss使用详细操作步骤,jboss使用详细操作步骤,jboss使用详细操作步骤,jboss使用详细操作步骤
JBOSS使用手册 JBOSS使用手册 JBOSS使用手册
Jbosside使用指南 jboss ide
JBOSS使用手册
因为JBoss代码遵循LGPL许可,你可以在任何商业应 用中免费使用它,而不用支付费用。JBoss是纯Java的Web应用服务器,为了保证JBoss服务器的正常运行,在安装JBoss之前首先要确保系统 已经安装了JDK。可以从...
JBOSSRULES使用文档
JBOSS的配置,JMX原理和应用,EJB3.0使用说明
jboss配置MySql的JNDI
JBOSS使用指南 在下载和安装JBoss之前,请开发者确认一下自己的机器是否安装了最新版的JVM。为运行JBoss 4.2.2GA,开发者必须提供Java 5虚拟机。在我们动身之前,请再次检查一下您是否安装了合适的JDK,而且JAVA_...
JBOSS,JBoss安装部署 JBOSS,JBoss安装部署
NULL 博文链接:https://liufangmeng.iteye.com/blog/1971266
Jboss使用指南,包括配置环境与布署项目,不错的入门书籍
JBoss启动JBoss启动JBoss启动JBoss启动JBoss启动JBoss启动JBoss启动JBoss启动 JBoss启动
JavaEE源代码 jboss-commonJavaEE源代码 jboss-commonJavaEE源代码 jboss-commonJavaEE源代码 jboss-commonJavaEE源代码 jboss-commonJavaEE源代码 jboss-commonJavaEE源代码 jboss-commonJavaEE源代码 jboss-...
jboss6下使用quartz两种方法,详细方法见内容