WebSphere中Java EE应用同时连接Oracle与H2数据库的上下文问题
解决WebSphere中同时访问Oracle和H2数据源的上下文冲突问题
这个问题的核心在于系统属性是JVM全局共享的——你来回修改Context.INITIAL_CONTEXT_FACTORY的操作会覆盖整个应用的默认上下文工厂,导致两段代码互相干扰。下面给你几个可行的解决方向:
方案1:使用局部环境参数创建独立的InitialContext(不修改全局属性)
不要通过System.setProperty()修改全局的上下文工厂,而是在创建InitialContext时传入局部环境哈希表,这样每个上下文使用自己的工厂配置,不会互相影响。
获取WebSphere配置的Oracle数据源
DataSource oracleDataSource = null; try { Hashtable<String, String> wasEnv = new Hashtable<>(); wasEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"); wasEnv.put(Context.URL_PKG_PREFIXES, "com.ibm.websphere.naming"); InitialContext wasCtx = new InitialContext(wasEnv); oracleDataSource = (DataSource) wasCtx.lookup("java:comp/env/jdbc/refDB"); } catch (NamingException e) { e.printStackTrace(); } return oracleDataSource.getConnection();
动态创建H2数据源的独立上下文
InitialContext h2Ctx = null; try { Hashtable<String, String> h2Env = new Hashtable<>(); h2Env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); h2Env.put(Context.URL_PKG_PREFIXES, "org.apache.naming"); h2Ctx = new InitialContext(h2Env); // 创建子上下文(仅在当前h2Ctx的命名空间内生效) h2Ctx.createSubcontext("java:"); h2Ctx.createSubcontext("java:comp"); h2Ctx.createSubcontext("java:comp/env"); h2Ctx.createSubcontext("java:comp/env/jdbc"); JdbcDataSource h2Ds = new JdbcDataSource(); h2Ds.setURL("jdbc:h2:mem:cachedb;DB_CLOSE_DELAY=-1"); h2Ctx.bind("java:comp/env/jdbc/CacheDb", h2Ds); // 从当前h2Ctx中查找H2数据源 DataSource h2DataSource = (DataSource) h2Ctx.lookup("java:comp/env/jdbc/CacheDb"); return h2DataSource.getConnection(); } catch (NamingException | SQLException e) { e.printStackTrace(); } finally { if (h2Ctx != null) { try { h2Ctx.close(); } catch (NamingException e) { e.printStackTrace(); } } }
关键注意:H2数据源必须从你创建的h2Ctx中查找,不能用无参的InitialContext(默认是WebSphere的上下文,找不到你绑定的H2数据源)。
方案2:直接在WebSphere中配置H2数据源(推荐)
其实完全不需要引入Tomcat的JAR包和动态创建上下文,WebSphere支持直接配置H2作为容器管理的数据源,这更符合Java EE规范,也更稳定:
- 将H2的JDBC驱动包(
h2-xxx.jar)放入WebSphere的共享库,或者你的应用的WEB-INF/lib目录 - 登录WebSphere控制台,导航到资源 > JDBC > 数据源,点击新建
- 选择H2的JDBC驱动(如果没有,先创建驱动定义,指定H2的驱动类
org.h2.Driver) - 配置H2的连接URL(
jdbc:h2:mem:cachedb;DB_CLOSE_DELAY=-1)、用户名密码等 - 在
ibm-web-bnd.xml中添加该数据源的引用绑定,格式和Oracle数据源一致 - 用和Oracle完全相同的方式lookup H2数据源即可
这种方案下,所有数据源都由WebSphere统一管理,不存在任何上下文冲突问题,是最推荐的做法。
为什么你之前的操作会出错?
当你调用System.setProperty()修改上下文工厂时,这个设置是全局的——整个JVM内的所有代码都会使用这个工厂类。比如你先设置了Tomcat的工厂,再去查找Oracle数据源时,WebSphere的上下文工厂已经被覆盖,自然会抛出NoInitialContextException。即使你后续改回WebSphere的工厂,H2的代码又会因为找不到Tomcat的工厂而报错。
内容的提问来源于stack exchange,提问作者simonalexander2005
相关产品推荐
相关产品推荐

