如何使用给定的 JNDI 名称连接到 Websphere 数据源?

Posted

技术标签:

【中文标题】如何使用给定的 JNDI 名称连接到 Websphere 数据源?【英文标题】:How do I connect to a Websphere Datasource with a given JNDI name? 【发布时间】:2011-11-02 06:59:49 【问题描述】:

我正在使用 Websphere Portal 7.0 并使用 RAD 8.0 创建一个 portlet。我的 portlet 正在尝试与远程服务器建立 db2 连接。我在本地编写了一个 java 程序来与服务器建立基本的 JDBC 连接并从表中获取记录。代码工作正常;但是,当我将代码添加到我的 portlet 以及 db2jcc4.jar 时,连接不起作用。我正在使用基本的:

Connection connection = DriverManager.getConnection("jdbc:db2://server:port/db:user=user;password=pw;");

我认为使用 Websphere 数据源是正确的方法。我知道数据源的 JNDI 名称,但我没有找到关于如何建立连接的明确示例。有几个例子使用了一个 DataSource 类(我输入了这个,这似乎不是来自本地 java 包,所以我在这里使用什么导入?)加上一个 Context。我遇到过这样的代码:

Context ctx = new InitialContext();
ctx.lookup("jdbc/xxxx");

... 有人可以帮我分解一下吗?

编辑 1

我已根据列出的答案更新了我的代码。我真的觉得我越来越近了。这是我的 getConnection() 方法:

private Connection getConnection() throws SQLException 
    javax.naming.InitialContext ctx = null;
    javax.sql.DataSource ds = null;
    System.out.println("Attempting connection..." + DateUtil.now() );
    try 
        ctx = new javax.naming.InitialContext();
        ds = (javax.sql.DataSource) ctx.lookup("java:comp/env/jdbc/db");
        connection = ds.getConnection();
     catch (NamingException e) 
        System.out.println("peformanceappraisalstatus: COULDN'T CREATE CONNECTION!");
        e.printStackTrace();
           
    System.out.println("connection: " + connection.getClass().getName() + " at " + DateUtil.now());
    return connection;

我的整个 web.xml 文件看起来像:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>PeformanceAppraisalStatus</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    <resource-ref>
        <description>
        Datasource connection to Db</description>
        <res-ref-name>jdbc/db</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
</web-app>

我看到一个错误,描述了你们告诉我的 Websphere 应该提示我做的事情,但没有:

SRVE0169I: Loading Web Module: PeformanceAppraisalStatus.
[8/23/11 18:08:02:166 CDT] 00000009 InjectionProc E   CWNEN0044E: A resource reference binding could not be found for the jdbc/db resource reference, defined for the PeformanceAppraisalStatus component.
[8/23/11 18:08:02:169 CDT] 00000009 InjectionEngi E   CWNEN0011E:  The injection engine failed to process bindings for the metadata.

是的,我知道我在整个应用程序中将性能拼写为性能。

解决方案

我是如此接近。以下是使其全部到位的缺失部分:

web.xml:
<resource-ref>      
    <description>
    Datasource connection to db</description>
    <res-ref-name>jdbc/db</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
    <mapped-name>jdbc/db</mapped-name>      
</resource-ref>

ibm-web-bnd.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd 
    xmlns="http://websphere.ibm.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_0.xsd"
    version="1.0">

    <virtual-host name="default_host" />


    <resource-ref name="jdbc/db" binding-name="jdbc/mydatasource" />
</web-bnd>

似乎 ibm-web-bnd.xml 文件处理了项目资源名称和 websphere 中的数据源之间的绑定。一旦我添加了这一行:

<resource-ref name="jdbc/db" binding-name="jdbc/mydatasource" />

Websphere Portal 似乎得到了安抚。我的代码现在正在工作并连接到数据库。

【问题讨论】:

如果您能将您的解决方案从问题提取到单独的答案,那就太好了。这将使主题更易于阅读。 【参考方案1】:

您需要在应用程序中定义一个资源引用,然后在部署期间将该逻辑资源引用映射到物理资源(数据源)。

在您的web.xml 中,添加以下配置(根据需要修改名称和属性):

<resource-ref>
    <description>Resource reference to my database</description>
    <res-ref-name>jdbc/MyDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

然后,在应用程序部署期间,WAS 会提示您将此资源引用 (jdbc/MyDB) 映射到您在 WAS 中创建的数据源。

在您的代码中,您可以获得与您在示例中显示的方式类似的 DataSource;但是,用于查找的 JNDI 名称实际上应该是您定义的资源引用的名称 (res-ref-name),而不是物理数据源的 JNDI 名称。此外,您需要在 res-ref-name 前面加上应用程序命名上下文 (java:comp/env/)。

Context ctx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/MyDB");

【讨论】:

@Jason,您的应用程序使用的是哪个版本的 servlet 规范?我上面描述的方法应该适用于任何版本,但是如果您使用的是 Servlet 2.5(WAS 7 支持该方法),则可以使用更简单的方法来使用 @Resource 注释。 我已经这样做了,但没有提示将资源引用关联到 WAS 中的数据源。现在环顾 WAS,看看是否有地方可以通过 portlet 设置手动完成。 WAS 应该提示您提供此信息,如果您不将资源引用映射到物理数据源,部署通常会失败。也许您指定了包含默认绑定的选项?您应该能够在 ISC 中的“应用程序 > 应用程序类型 > WebSphere 企业应用程序 > [your_application] > 资源引用”中看到映射这些的选项。如果您没有看到该选项或没有看到您在此处列出的资源参考,则可能是您的应用中的某些内容配置错误。 RAD 将创建特定于 WAS 的部署文件,即 .xmi 文件,这些文件将自动做出阻止部署提示您的选择。您可以在 RAD 中编辑这些文件,也可以尝试将它们从 RAD 构建的工件中排除。或者,正如雪莱所说,您可以在部署后重新映射它们。 好吧,我一直说是。我实际上是通过 Websphere Portal 的 Admin --> Portlet Management 上传 .WAR 文件。我们在这里谈论的是同一件事吗?【参考方案2】:

要从数据源获取连接,下面的代码应该可以工作:

import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

Context ctx = new InitialContext();
DataSource dataSource = ctx.lookup("java:comp/env/jdbc/xxxx");
Connection conn = dataSource.getConnection();

// use the connection

conn.close();

虽然您可以直接查找 Websphere Data Sources 配置中定义的数据源(即通过 websphere 控制台),但从 java:comp/env/jdbc/xxxx 查找意味着需要在 web 中有一个条目.xml:

<resource-ref>
    <res-ref-name>jdbc/xxxx</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

这意味着数据源可以映射到每个应用程序的基础上,如果您想将应用程序指向不同的数据源,则无需更改数据源的名称。这在将应用程序部署到需要指向不同数据库的不同服务器(例如 test、preprod、prod)时很有用。

【讨论】:

【参考方案3】:

服务的 DNS

在理解 JNDI 是一个服务定位器的情况下,需要接近它。当所需的服务托管在与应用程序相同的服务器/节点上时,您可以使用 InitialContext。

更复杂的是,在 Web Sphere 中定义数据源(至少在 4.0 中)允许您在不同程度上定义可见性。基本上,它将命名空间添加到环境中,客户端必须知道资源的托管位置。

Simple example.

javax.naming.InitialContext ctx = new javax.naming.InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/DataSourceAlias");

这是 IBM 的 reference page。

如果您尝试从不在 J2EE 容器中的应用程序中引用数据源,则需要一种稍微不同的方法,首先需要在类路径中添加一些 J2EE 客户端 jar。 http://www.coderanch.com/t/75386/Websphere/lookup-datasources-JNDI-outside-EE

【讨论】:

看到就是这样...我认为 JNDI 名称是一种可用于查找实际连接信息的键,但我研究得越多,JNDI 似乎就越大。我很欣赏高级别的解释,但我试图找到更多细节。向 ibm 询问“以下是如何从 portlet 内部使用 jndi 连接到 websphere 数据源”的示例就太过分了…… 我对你有感觉。如果我手头有旧代码库,我会尝试发布一些真实示例。事实上,要知道有许多活动部件都必须排队才能工作。【参考方案4】:

杰森,

这就是它的工作原理。

Localnamespace - java:comp/env 是应用程序使用的本地名称空间。您在其中使用的名称 jdbc/db 只是一个别名。它不是指物理资源。

在部署期间,此别名应映射到在 WAS/WPS 运行时定义的物理资源(在您的情况下为数据源)。

这实际上存储在 ejb-bnd.xmi 文件中。在最新版本中,XMI 被 XML 文件替换。这些文件称为绑定文件。

HTH 芒露

【讨论】:

【参考方案5】:

对于像我这样的人,只需要有关如何使用 JNDI 查找从 Java 连接到 (DB2) WAS 数据源的信息(使用 IBM Websphere 8.5.5 & DB2 Universal JDBC Driver Provider with implementation class:com.ibm.db2 .jcc.DB2ConnectionPoolDataSource):

public DataSource getJndiDataSource() throws NamingException 
    DataSource datasource = null;
    InitialContext context = new InitialContext();
    // Tomcat/Possibly others: java:comp/env/jdbc/myDatasourceJndiName
    datasource = (DataSource) context.lookup("jdbc/myDatasourceJndiName");
    return datasource;

【讨论】:

【参考方案6】:

查找以下代码以从您的 Web 应用服务器获取数据库连接。只需在应用服务器中创建数据源并使用以下代码获取连接:

// To Get DataSource
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/abcd");
// Get Connection and Statement
Connection c = ds.getConnection();
stmt = c.createStatement();

导入命名和 sql 类。无需添加任何 xml 文件或编辑项目中的任何内容。 就是这样。。

【讨论】:

以上是关于如何使用给定的 JNDI 名称连接到 Websphere 数据源?的主要内容,如果未能解决你的问题,请参考以下文章

休眠错误配置:未将工厂绑定到 JNDI,未配置 JNDI 名称

Oracle JDBC 驱动程序未在旧版 Web 应用程序中使用 JNDI 连接到数据库

如何在 jndi 中启用 ldap over ssl

如何在不指定数据库名称的情况下连接到 PostgreSQL?

使用 JMS 连接到 IBM MQ

如何从 Websphere 服务器连接到 Weblogic JMS?