如何在 Tomcat 中为数据库连接池配置 JNDI 数据源
本教程向您展示如何在 Tomcat 中创建表示 JDBC 数据源的 JNDI 资源,然后如何配置 Java Web 应用程序以访问 JNDI 数据源。使用 JNDI 数据源的好处是:利用容器提供的数据库连接池服务,即Tomcat使用Commons DBCP和Commons Pool作为实现(tomcat-dbcp.jar)。外部化数据库连接并使其独立于 Web 应用程序本身。在容器中部署的应用程序
本教程向您展示如何在 Tomcat 中创建表示 JDBC 数据源的 JNDI 资源,然后如何配置 Java Web 应用程序以访问 JNDI 数据源。使用 JNDI 数据源的好处是:
- 利用容器提供的数据库连接池服务,即Tomcat使用tomcat-jdbc作为实现。
- 外部化数据库连接并使其独立于 Web 应用程序本身。
- 在容器中部署的应用程序之间共享数据库连接。
以下示例在 Tomcat 9 和 MySQL Database 8 中进行了测试。
1. MySQL 数据库示例
首先,我们需要创建一个示例数据库。让我们执行以下 MySQL 脚本:
create database usersdb;
use usersdb;
CREATE TABLE `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`email` varchar(45) NOT NULL,
PRIMARY KEY (`user_id`)
);
这将创建一个名为usersdb的数据库和一个名为users的表。请记住在此表中插入一些虚拟数据。
要从 Java 应用程序与 MySQL 数据库交互,MySQL Connector/J库必须存在于类路径中。在这里,我们需要将mysql-connector-java-VERSION-bin.jar文件复制到$CATALINA_BASE/lib目录下。如果您的计算机上只有一个 Tomcat 实例,则$CATALINA_BASE是 Tomcat 的安装目录,例如Windows 平台上的c:\Program Files\Apache Software Foundation\Tomcat 9.0。这样做有助于 Tomcat 在发现 JNDI 数据源配置时加载 MySQL JDBC 驱动程序。
2.配置上下文
要为上面的 MySQL 数据库声明 JNDI 数据源,请创建一个具有以下内容的Resource XML 元素:
<?xml version='1.0' encoding='utf-8'?>
<Context path="/JNDIDataSourceExample">
<Resource
name="jdbc/UsersDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
maxActive="100"
maxIdle="30"
maxWait="10000"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/usersDB"
username="root"
password="root"
/>
</Context>
在context.xml文件的根元素<Context>中添加此元素。context.xml文件可以驻留在两个位置(如果不存在,则创建一个):
- 在Web 应用程序的/META-INF目录中:JNDI 数据源仅对应用程序本身可用,因此不能与其他应用程序共享。此外,这使得配置依赖于应用程序。
- 在$CATALINA_BASE/conf目录中:这是首选位置,因为 JNDI 数据源将可用于所有 Web 应用程序并且它独立于任何应用程序。
因此,我们在$CATALINA_BASE/conf目录下的context.xml文件中声明上述Resource元素。下表描述了上述配置中指定的属性:
属性名称 | 描述 |
姓名 | 资源的名称。 |
授权 | 指定应用代码的认证机制,可以是Application或Container。 |
类型 | Web 应用程序在查找此资源时所期望的完全限定的 Java 类名。 |
最大活动 | 池中的最大数据库连接数。设置为 -1 表示没有限制。 |
最大空闲 | 保留在池中的最大空闲数据库连接数。设置为 -1 表示没有限制。 |
最大等待 | 等待数据库连接可用的最长时间(以毫秒为单位),在本示例中为 10 秒。如果超过此超时,则会引发异常。设置为 -1 以无限期等待。 |
驱动程序类名 | 数据库驱动程序的完全限定 Java 类名。对于 MySQL Connector/J,它是com.mysql.jdbc.Driver。 |
网址 | JDBC 连接 URL。 |
用户名 | MySQL 数据库用户名。 |
密码 | MySQL 数据库用户密码。 |
有关属性的更多信息,请访问本教程末尾提到的参考链接。
笔记:
- 如果您在 Eclipse IDE 中使用 Tomcat,则需要修改Servers项目下的context.xml文件。那是因为 Eclipse 复制了 Tomcat 配置:
- 如果在 web 应用程序的META-INF目录和$CATALINA_BASE/conf目录下的context.xml文件中都声明了两个具有相同名称的资源,则内部版本优先。
3.配置web.xml
将以下声明添加到web.xml文件中:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>JNDIDataSourceExample</display-name>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/UsersDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
为了使 JNDI DataSource 可用于指定命名空间jdbc/UsersDB下的应用程序,这是必需的。
4.编写一个测试JSP页面
现在,创建一个 JSP 页面 ( UsersList.jsp ) 来测试我们所做的配置:
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<sql:query var="listUsers" dataSource="jdbc/UsersDB">
select username, email from users;
</sql:query>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Users List</title>
</head>
<body>
<div align="center">
<table border="1" cellpadding="5">
<caption><h2>List of users</h2></caption>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
<c:forEach var="user" items="${listUsers.rows}">
<tr>
<td><c:out value="${user.username}" /></td>
<td><c:out value="${user.email}" /></td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
在这里,我们使用JSTL 的 SQL 标记查询对数据库进行 SELECT 查询。请注意,dataSource属性是指在web.xml文件中声明的 JNDI 资源名称:
<sql:query var="listUsers" dataSource="jdbc/UsersDB">
select username, email from users;
</sql:query>
5. 编写一个测试 Java servlet
我们可以使用 Java 代码查找配置的 JNDI 数据源,如下所示:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/UsersDB");
Connection conn = ds.getConnection();
获取到连接后,我们可以将其作为简单的 JDBC 代码使用:
Statement statement = conn.createStatement();
String sql = "select username, email from users";
ResultSet rs = statement.executeQuery(sql);
// iterates over the result set...
这是示例 Java servlet 的源代码:
package net.codejava.jdbc;
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;
/**
* This servlet class demonstrates how to access a JNDI DataSource that
* represents a JDBC connection.
* @author www.codejava.net
*/
@WebServlet("/listUsers")
public class UsersListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
try {
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/UsersDB");
Connection conn = ds.getConnection();
Statement statement = conn.createStatement();
String sql = "select username, email from users";
ResultSet rs = statement.executeQuery(sql);
int count = 1;
while (rs.next()) {
writer.println(String.format("User #%d: %-15s %s", count++,
rs.getString("username"), rs.getString("email")));
}
} catch (NamingException ex) {
System.err.println(ex);
} catch (SQLException ex) {
System.err.println(ex);
}
}
}
或者,我们可以使用@Resource注释 ( javax.annotation.Resource ) 而不是上面的查找代码。例如,在 servlet 中声明一个名为dataSource的字段,如下所示:
@Resource(name = "jdbc/UsersDB")
private DataSource dataSource;
Tomcat 会在发现这个注解时查找指定的资源名称并注入一个实际的实现。因此,servlet 代码如下所示:
package net.codejava.jdbc;
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.annotation.Resource;
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;
/**
* This servlet class demonstrates how to access a JNDI DataSource that
* represents a JDBC connection.
*
* @author www.codejava.net
*/
@WebServlet("/listUsers")
public class UsersListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Resource(name = "jdbc/UsersDB")
private DataSource dataSource;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
try {
Connection conn = dataSource.getConnection();
Statement statement = conn.createStatement();
String sql = "select username, email from users";
ResultSet rs = statement.executeQuery(sql);
int count = 1;
while (rs.next()) {
writer.println(String.format("User #%d: %-15s %s", count++,
rs.getString("username"), rs.getString("email")));
}
} catch (SQLException ex) {
System.err.println(ex);
}
}
}
参考:
JNDIDataSourceExample.zip | 【Eclipse项目】 | 393 KB |
更多推荐
所有评论(0)