Java 中的 Tomcat DataSource JNDI 示例
欢迎来到 Tomcat DataSource JNDI 示例教程。我们在上一篇教程中查看了JDBC DataSource,并学习了如何在独立 Java 应用程序中使用它。
Tomcat 数据源 JNDI
当我们将 DataSource 与JNDI 上下文一起使用时,DataSource 的实际好处就显现出来了。例如,在 servlet 容器中部署的 Web 应用程序中的连接池。大多数流行的 servlet 容器通过资源配置和 JNDI 上下文为 DataSource 提供内置支持。这有助于我们仅用几行配置即可创建和使用 DataSource 连接池。本教程旨在提供 Tomcat DataSource JNDI 配置示例。Apache Tomcat 提供了三种在 JNDI 上下文中配置 DataSource 的方法。
- 应用程序 context.xml - 这是配置 DataSource 的最简单方法,我们只需要 META-INF 目录中的一个 context.xml 文件。我们必须在上下文文件中定义资源元素,容器将负责加载和配置它。这种方法很简单,但也有一些缺点;
- 由于上下文文件与 WAR 文件捆绑在一起,因此我们需要为每个小的配置更改构建和部署新的 WAR。如果您的应用程序在分布式环境中运行,或者您的应用程序需要部署在不同的测试环境(如 QA、IT、PROD 等)中,也会出现同样的问题。
- 数据源是由容器创建的,仅供应用程序使用,因此不能全局使用。我们不能在多个应用程序之间共享数据源。
- 如果存在定义同名的全局数据源(server.xml),则会忽略应用程序数据源。
- 服务器 context.xml - 如果服务器中有多个应用程序,并且您想要在它们之间共享数据源,我们可以在服务器 context.xml 文件中定义它。此文件位于
apache-tomcat/conf
目录中。服务器 context.xml 文件的范围是应用程序,因此如果您定义一个包含 100 个连接的数据源连接池,并且有 20 个应用程序,那么将为每个应用程序创建数据源。这将导致 2000 个连接,这显然会消耗所有数据库服务器资源并损害应用程序性能。 - server.xml 和 context.xml - 我们可以在 server.xml 元素中定义 DataSource,从而在全局级别定义它们
GlobalNamingResources
。如果我们使用这种方法,那么我们需要ResourceLink
从 context.xml 文件定义一个特定于服务器或应用程序的文件。当您希望在服务器上运行的多个应用程序之间共享一个公共资源池时,这是首选方法。关于资源链接,是否在服务器级别上下文 xml 文件或应用程序级别定义它取决于您的要求。
让我们来看看 Java Web 应用程序中的 Tomcat DataSource JNDI 示例。有关测试数据设置,请参阅我上一篇关于JDBC DataSource 示例的文章。
Tomcat DataSource JNDI 配置示例 - server.xml
在 tomcat server.xml 文件中添加以下代码。代码应添加到元素中GlobalNamingResources
。还要确保数据库驱动程序存在于 tomcat lib 目录中,因此在这种情况下,mysql jdbc jar 必须存在于 tomcat lib 中。
<Resource name="jdbc/MyDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/UserDB"
username="pankaj"
password="pankaj123"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
这里我们创建 JNDI 上下文,名称为jdbc/MyDB
DataSource 类型。我们在 url、用户名、密码和 driverClassName 属性中传递数据库配置。连接池属性在 maxActive、maxIdle 和 minIdle 属性中定义。
Tomcat DataSource JNDI 资源链接配置-context.xml
在服务器 context.xml 文件中添加以下代码。
<ResourceLink name="jdbc/MyLocalDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource" />
请注意,资源链接名称与全局链接不同,我们必须在我们的 Java 程序中使用此名称来获取数据源。
Tomcat 数据源 JNDI 示例
创建一个名为JDBCDataSourceTomcat的动态 Web 应用程序,然后使用以下代码创建一个 Servlet。
package com.journaldev.jdbc.datasource;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
@WebServlet("/JDBCDataSourceExample")
public class JDBCDataSourceExample extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Context ctx = null;
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try{
ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select empid, name from Employee");
PrintWriter out = response.getWriter();
response.setContentType("text/html");
out.print("<html><body><h2>Employee Details</h2>");
out.print("<table border=\"1\" cellspacing=10 cellpadding=5>");
out.print("<th>Employee ID</th>");
out.print("<th>Employee Name</th>");
while(rs.next())
{
out.print("<tr>");
out.print("<td>" + rs.getInt("empid") + "</td>");
out.print("<td>" + rs.getString("name") + "</td>");
out.print("</tr>");
}
out.print("</table></body><br/>");
//lets print some DB information
out.print("<h3>Database Details</h3>");
out.print("Database Product: "+con.getMetaData().getDatabaseProductName()+"<br/>");
out.print("Database Driver: "+con.getMetaData().getDriverName());
out.print("</html>");
}catch(NamingException e){
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
rs.close();
stmt.close();
con.close();
ctx.close();
} catch (SQLException e) {
System.out.println("Exception in closing DB resources");
} catch (NamingException e) {
System.out.println("Exception in closing Context");
}
}
}
}
请注意,我使用的是基于 Servlet 3 注释的配置,它将在 Tomcat 7 或更高版本中工作。如果您使用的是较低版本的 Tomcat,则需要对 servlet 代码进行一些修改,以删除 WebServlet 注释并在 web.xml 文件中进行配置。我们感兴趣的 servlet 代码部分;
ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
这是获取应用程序要使用的 JNDI 资源定义的方法。我们也可以这样写;
ctx = new InitialContext();
Context initCtx = (Context) ctx.lookup("java:/comp/env");
DataSource ds = (DataSource) initCtx.lookup("jdbc/MyLocalDB");
我还打印了一些数据库信息来检查我们连接的是哪个数据库。现在,当您运行应用程序时,您将看到以下输出。让我们看看切换数据库服务器有多么容易,因为我们使用的是 Tomcat DataSource。您只需要更改数据库属性。因此,如果我们必须切换到 Oracle 数据库,我的资源配置将如下所示。
<Resource name="jdbc/MyDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:orcl"
username="hr"
password="oracle"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
当我们重新启动服务器并运行应用程序时,它将连接到 Oracle 数据库并产生以下结果。这就是 Tomcat DataSource JNDI 配置示例教程的全部内容,您也可以在 context.xml 文件中以类似的方式定义资源。