前些日子,农总行的客户有个需求,需要跨Sybase ASE和Sybase IQ两个数据库操作,并且保证事务的完整性,而且客户不希望通过数据库层来保证事务,只希望在代码层控制。
专门写了一个TestCase,准备同外围访问通过remote jndi方式访问datasource。
Hashtable evn = new Hashtable();
evn.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
evn.put(Context.PROVIDER_URL, "jnp://localhost:1299/");
InitialContext jndiContext = new InitialContext(evn);
DataSource ds = (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测试,代码主体如下:
public void init() throws ServletException {
UserTransaction utx = null;
try {
InitialContext jndiContext= new InitialContext();
utx= (javax.transaction.UserTransaction)jndiContext.lookup("UserTransaction");
utx.begin();
insertSQL_();
insertSybase();
utx.commit();
} catch (Exception e) {
if(utx!=null){
utx.rollback();//此处异常代码省略
}
}
}
private void insertSQL_() throws Exception{
Connection conn1 = createXAConnection("MSSQLXADS");
insertData(conn1); //插入数据测试,代码省略
}
private void insertSybase()throws Exception{
Connection conn2 = createXAConnection("XASybaseDS");
insertDataSybase(conn2); //插入数据测试,代码省略
throw new Exception(""); //此处做异常回滚测试
}
private Connection createXAConnection(String jndiname)throws Exception{
InitialContext jndiContext;
try {
jndiContext = new InitialContext();
DataSource ds = (DataSource)jndiContext.lookup(jndiname);
return ds.getConnection();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}