Tutorial

Tomcat DataSource JNDI Example in Java

Published on August 3, 2022
author

Pankaj

Tomcat DataSource JNDI Example in Java

Welcome to Tomcat DataSource JNDI Example Tutorial. We looked at the JDBC DataSource in the last tutorial and learned how to use that in standalone java application.

Tomcat DataSource JNDI

tomcat datasource, jndi example, tomcat jndi, jndi tutorial Actual benefit of DataSource comes when we use it with a JNDI Context. For example, connection pool in a web application deployed in a servlet container. Most of the popular servlet containers provide built-in support for DataSource through Resource configuration and JNDI context. This helps us in creating and using DataSource connection pool with just few lines of configuration. This tutorial is aimed to provide Tomcat DataSource JNDI configuration example. Apache Tomcat provide three ways to configure DataSource in JNDI context.

  1. Application context.xml - This is the easiest way to configure DataSource, all we need is a context.xml file in META-INF directory. We have to define Resource element in the context file and container will take care of loading and configuring it. The approach is simple but it has some drawbacks;
    • Since the context file is bundled with the WAR file, we need to build and deploy new WAR for every small configuration change. Same issue comes if your application works in distributed environment or your application needs to be deployed in different testing environments such as QA, IT, PROD etc.
    • The datasource is created by container for the application usage only, so it can’t be used globally. We can’t share the datasource across multiple applications.
    • If there is a global datasource (server.xml) defined with same name, the application datasource is ignored.
  2. Server context.xml - If there are multiple applications in the server and you want to share DataSource across them, we can define that in the server context.xml file. This file is located in apache-tomcat/conf directory. The scope of server context.xml file is application, so if you define a DataSource connection pool of 100 connections and there are 20 applications then the datasource will be created for each of the application. This will result in 2000 connections that will obviously consume all the database server resources and hurt application performance.
  3. server.xml and context.xml - We can define DataSource at global level by defining them in the server.xml GlobalNamingResources element. If we use this approach, then we need to define a ResourceLink from context.xml file of server or application specific. This is the preferred way when you are looking to share a common resource pool across multiple applications running on the server. Regarding resource link, whether to define it at server level context xml file or application level depends on your requirement.

Let’s head over to the Tomcat DataSource JNDI example in java web application. For the test data setup, please refer to my last article about JDBC DataSource Example.

Tomcat DataSource JNDI Configuration Example - server.xml

Add below code in the tomcat server.xml file. The code should be added in the GlobalNamingResources element. Also make sure that database driver is present in the tomcat lib directory, so in this case mysql jdbc jar have to be present in the 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"/>

Here we are creating JNDI context with name as jdbc/MyDB which is a type of DataSource. We are passing database configurations in url, username, password and driverClassName attribute. Connection pooling properties are defined in maxActive, maxIdle and minIdle attributes.

Add below code in the server context.xml file.

<ResourceLink name="jdbc/MyLocalDB"
                global="jdbc/MyDB"
                auth="Container"
                type="javax.sql.DataSource" />

Notice that resource link name is different than global link, we have to use this name in our java program to get the DataSource.

Tomcat DataSource JNDI Example

Create a dynamic web application with name JDBCDataSourceTomcat and then create a Servlet with below code.

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");
			}
			
		}
	}

}

Notice that I am using Servlet 3 Annotation based configuration and it will work in Tomcat 7 or higher versions. If you are using lower version of Tomcat then you need to do some modifications to the servlet code, to remove WebServlet annotation and configure in web.xml file. The part of servlet code that we are interested in;

ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");

This is the way to get the JNDI resources defined to be used by the application. We could have written it in this way too;

ctx = new InitialContext();
Context initCtx  = (Context) ctx.lookup("java:/comp/env");
DataSource ds = (DataSource) initCtx.lookup("jdbc/MyLocalDB");

I am also printing some database information to check which database we are connected. Now when you will run the application, you will see following output. Tomcat DataSource JNDI Example MySQL, JNDI DataSource MySQL Let’s see how easy it is to switch the database server because we are using Tomcat DataSource. All you need is to change the Database properties. So if we have to switch to Oracle database, my Resource configuration will look like below.

<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"/>

And when we restart the server and run the application, it will connect to Oracle database and produce below result. Tomcat DataSource JNDI Example Oracle That’s all for Tomcat DataSource JNDI configuration example tutorial, you can define the resource in similar way in context.xml files too.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Pankaj

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
April 16, 2021

Can I configure primary and secondary datasource in the tomcat context.xml? I tried it using comma separated values and it worked. It just connects to the secondary if the primary is not available. But I guess that cannot work during runtime. I have a spring based web application running on tomcat. I need my application to connect to a secondary database if the connection to the primary times out. This should happen at runtime. One way I could think was to define another datasource and then when craeting connection, catch the exceptiona nd connect to secondary . Is there an elegant way of doing it from config instead of code.

- vish

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    January 25, 2021

    Do we need SERVER.XML and CONTEXT.XML, or just one file? You don’t say. Can I just update CONTEXT.XML to configure JNDI?

    - Jason

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      April 17, 2020

      very good post…helped alot

      - sushma

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        April 16, 2020

        Sir I’m getting an exception called javax.naming.NameNotFoundException :Name [jdbc/MyLocalDB] is not bound in this Context. Unable to find [jdbc]… I wrote the database connection code in a seperate file called DBUtil.java. Kindly help me with a solution. Thank You.

        - vishnu

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          April 1, 2020

          H, I have followed this tutorial (for Oracle) but keep getting the following errors - java.lang.NullPointerException com.seagate.stst.contactlist.JDBCDataSourceExample.doGet(JDBCDataSourceExample.java:64) javax.servlet.http.HttpServlet.service(HttpServlet.java:621) javax.servlet.http.HttpServlet.service(HttpServlet.java:728) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) Can you please help!?

          - Dearbhla

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            March 16, 2020

            Thanks for this great article. I’ve a problem that I suppose is simple to solve but I can’t find the way. My scenario is: one war (ex.: myapp.war) should serve multiple context (ex.: /app1, /app2, etc…) and each context must have his own database. How can I configure Tomcat for this scenario? Many thanks in advance to anyone can help me

            - Ferdinando Cecchini

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              March 9, 2020

              Hi Pankaj, Thanks for all of the above. Though… Using JNDI for datasources really hard-wires my application to Tomcat (with context.xml and web.xml). Thus, I cannot unit-test my DB-code outside a running Tomcat, if the connection is to be obtained using JNDI. It is not hard to establish a JDCB-connection from scratch - that is not the issue. The problem is, that I want to configure for the connection properties used by JNDI from outside Tomcat (ie the url, username, password) - preferrably in a Java-properties file. In a context.xml I cannot see a way to do that elegantly, without having to specify url, user, pwd properties with -D at JVM level - then I can revert to the ${…somename…} pattern in both context.xml and web.xml. I have tried to find ways to have Tomcat accept a Java-properties file up-front, but no luck. A WEB-application is not portable, if context.xml has to be modified for each deploy, and it is not JDCB-testable at low level, if it requires a Tomcat to be running. Can you see my point? How to do JNDI JDCB-connects out-side Tomcat? Please tell, if you have any suggestions. Best, Aron

              - Aron Olsen

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                January 22, 2020

                Hi sir, i connected database mysql with tomcat but was getting errors like… 22-Jan-2020 22:36:28.192 WARNING [main] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [197] milliseconds. & 22-Jan-2020 22:36:30.776 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [“http-nio-8080”] . Could you please help me.

                - chika

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  December 10, 2019

                  Hi Could you please create the data source for microsoft sql server/ Regard Muhmmad

                  - Muhammad Zahid

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    June 26, 2019

                    Good information. Thank you very much.

                    - Ramesh

                      Try DigitalOcean for free

                      Click below to sign up and get $200 of credit to try our products over 60 days!

                      Sign up

                      Join the Tech Talk
                      Success! Thank you! Please check your email for further details.

                      Please complete your information!

                      Featured on Community

                      Get our biweekly newsletter

                      Sign up for Infrastructure as a Newsletter.

                      Hollie's Hub for Good

                      Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

                      Become a contributor

                      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                      Welcome to the developer cloud

                      DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

                      Learn more