Java中的Tomcat数据源JNDI示例

时间:2020-02-23 14:35:38  来源:igfitidea点击:

欢迎使用Tomcat DataSource JNDI示例教程。
我们在上一教程中查看了JDBC DataSource,并学习了如何在独立的Java应用程序中使用它。

Tomcat数据源JNDI

当我们将其与JNDI上下文一起使用时,DataSource的实际好处就来了。
例如,Web应用程序中的连接池部署在Servlet容器中。
大多数流行的servlet容器通过资源配置和JNDI上下文提供对DataSource的内置支持。
这有助于我们通过几行配置来创建和使用DataSource连接池。
本教程旨在提供Tomcat DataSource JNDI配置示例。

Apache Tomcat提供了三种在JNDI上下文中配置DataSource的方法。

  • 应用程序context.xml –这是配置DataSource的最简单方法,我们需要的是META-INF目录中的context.xml文件。
    我们必须在上下文文件中定义Resource元素,容器将负责加载和配置它。
    这种方法很简单,但是也有一些缺点;由于上下文文件与WAR文件捆绑在一起,因此我们需要为每个小的配置更改构建并部署新的WAR。
    如果您的应用程序在分布式环境中运行,或者您的应用程序需要部署在不同的测试环境(例如QA,IT,PROD等)中,也会出现同样的问题。

  • 数据源是由容器创建的,仅供应用程序使用,因此不能在全球范围内使用。
    我们无法在多个应用程序之间共享数据源。

  • 如果存在使用相同名称定义的全局数据源(server.xml),则将忽略应用程序数据源。

  • 服务器context.xml –如果服务器中有多个应用程序,并且您希望在它们之间共享数据源,我们可以在服务器context.xml文件中对其进行定义。
    该文件位于" apache-tomcat/conf"目录中。
    服务器context.xml文件的范围是application,因此,如果您定义一个100个连接的DataSource连接池,并且有20个应用程序,则将为每个应用程序创建数据源。
    这将导致2000个连接,这些连接显然将消耗所有数据库服务器资源,并损害应用程序性能。

  • server.xml和context.xml –我们可以通过在server.xmlGlobalNamingResources元素中定义它们来在全局级别定义DataSource。
    如果使用这种方法,则需要从特定于服务器或者应用程序的context.xml文件中定义一个" ResourceLink"。
    当您希望在服务器上运行的多个应用程序之间共享公用资源池时,这是首选方法。
    关于资源链接,是在服务器级别的上下文xml文件还是在应用程序级别定义它取决于您的要求。

让我们来看一下Java Web应用程序中的Tomcat DataSource JNDI示例。

对于测试数据设置,请参考我关于JDBC数据源示例的上一篇文章。

Tomcat数据源JNDI配置示例– server.xml

在tomcat server.xml文件中添加以下代码。
该代码应添加到" GlobalNamingResources"元素中。
还要确保tomcat lib目录中存在数据库驱动程序,因此在这种情况下,tomcat lib中必须存在mysql jdbc jar。

<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="hyman" 
    password="hyman123" 
    
    maxActive="100" 
    maxIdle="20" 
    minIdle="5" 
    maxWait="10000"

其中我们正在创建名称为jdbc/MyDB的JNDI上下文,这是一种数据源。
我们通过url,用户名,密码和driverClassName属性传递数据库配置。
连接池属性在maxActive,maxIdle和minIdle属性中定义。

Tomcat数据源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.theitroad.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"

重新启动服务器并运行该应用程序.