Configure JNDI Datasource in Tomcat
Almost all web applications need to access a database. So we need to be aware what the best practices are in order to configure these databases efficiently. A database connection is expensive to make, that is why most of the servlet containers provide built-in support for connection pooling. We can leverage this connection pooling in tomcat by registering the datasource via the JNDI context. In this tutorial we explain how to configure a datasource in tomcat and how to obtain an instance of this datasource via JNDI.
Prerequisites
We are configuring a MySQL database. This example assumes you’ve already created a database and installed the driver. If you haven’t installed the driver, download the MySQL driver and add the driver in the $TOMCAT_HOME/lib
folder.
Configure Datasource in tomcat – server.xml
Add the following Resource
element to the GlobalNamingResource
element inside the $TOMCAT_HOME/conf/server.xml
file. Here we are creating a Resource
of type javax.sql.DataSource
with a JNDI name of jdbc/DatabaseName. As we are using MySQL database, we provide the com.mysql.jdbc.Driver
driver class. Note that if you are using a different database, you should change the url and driverClassName accordingly. The other properties are used to configure the connection pool for our DataSource
.
<Server>
...
<GlobalNamingResources>
<Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
username="user" password="password"
url="jdbc:mysql://localhost:3306/DB_USERS"
driverClassName="com.mysql.jdbc.Driver"
initialSize="5" maxWait="5000"
maxActive="120" maxIdle="5"
validationQuery="select 1"
poolPreparedStatements="true"/>
</GlobalNamingResources>
...
</Server>
Configure ResourceLink – context.xml
Next, we add the ResourceLink
element to the Context
element inside the $TOMCAT_HOME/conf/context.xml
. This will create a linked resource to the global JNDI resource. Note that the name differs from the global JNDI resource. We should use the name of the resource link in our application.
<Context>
...
<ResourceLink name="jdbc/LocalDatabaseName"
global="jdbc/DatabaseName"
type="javax.sql.DataSource"/>
</Context>
At this point you have successfully configured a datasource in tomcat. When you run tomcat, the data source should be available under the JNDI name: jdbc/LocalDatabaseName
.
Define preconfigured JNDI Datasource – web.xml
Then, we register the ResourceLink
JNDI name – under which the application will look up the preconfigured data source – inside the /WEB-INF/web.xml
servlet descriptor of our application. I noticed this isn’t mandatory, but it helps to inform your colleagues of which data sources are available.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<!-- preconfigured jndi datasource-->
<resource-ref>
<res-ref-name>jdbc/EmployeeDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
DataSource Lookup via JNDI
Now that our data-source is configured, we can look up the datasource via JNDI. First, we create an instance of the InitialContext
. Then look up the context using the standard "java:comp/env"
JNDI name. Finally, we look up the DataSource
via the "jdbc/LocalDatabaseName"
JNDI name.
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource dataSource = (DataSource) envCtx.lookup("jdbc/LocalDatabaseName");
We can also immediately look up the DataSource
via the "java:/comp/env/jdbc/LocalDatabaseName"
JNDI name.
Context initCtx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup("java:/comp/env/jdbc/LocalDatabaseName");
We can also obtain an instance of the DataSource
by injecting it via the @Resource
annotation in a servlet environment.
@Resource(name="jdbc/LocalDatabaseName")
private DataSource dataSource;
Example Servlet JNDI DataSource lookup via @Resource
Finally, we show you a simple example how to obtain a reference of the DataSource
instance in a servlet environment. This example assumes that we configured a DataSource
under the jdbc/LocalDatabaseName
JNDI name. We also created a tbl_users
table and inserted a couple of dummy records.
package com.memorynotfound.jndi;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.sql.DataSource;
import java.io.*;
import java.sql.*;
@WebServlet(urlPatterns = "/*")
public class WelcomeServlet extends HttpServlet {
@Resource(name="jdbc/LocalDatabaseName")
private DataSource ds;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Statement stmt = null;
ResultSet rs = null;
try {
Connection con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select id, name, email from tbl_users");
PrintWriter out = resp.getWriter();
resp.setContentType("text/html");
out.write("<html>");
out.write("<body>");
out.write("<h3>Database Records</h3>");
while(rs.next()) {
out.write("id: " + rs.getInt("id") + " ");
out.write("name: " + rs.getString("name") + " ");
out.write("email: " + rs.getString("email") + " ");
out.write("</br>");
}
//lets print some DB information
out.write("<h3>Database Meta Data</h3>");
DatabaseMetaData metaData = con.getMetaData();
out.write("Database Product: " + metaData.getDatabaseProductName() + "<br/>");
out.write("Database Version: " + metaData.getDatabaseMajorVersion() + "."
+ metaData.getDatabaseMinorVersion() + "<br/>");
out.write("Database Driver: " + metaData.getDriverName() + "<br/>");
out.write("Database Driver version: " + metaData.getDriverMajorVersion() + "."
+ metaData.getDriverMinorVersion() + "<br/>");
out.write("Database user: " + metaData.getUserName());
out.write("</html>");
} catch (SQLException e) {
e.printStackTrace();
} finally{
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
} catch (SQLException e) {
System.out.println("Exception in closing DB resources");
}
}
}
}
Demo
URL: http://localhost:8080/jndi/