Wednesday, November 5, 2014

JNDI vs JDBC

JNDI is a protocol / mechanism used to lookup data / information, resources from a SPI that obeys the JNDI format. JNDI is available for manipulating naming services and directory services only. Examples include JNDI trees of EJB Containers, LDAP Directory Servers etc...


JDBC is a database specific protocol that Database vendors support for Java Data Access.


JNDI is used when your are trying to advertise and lookup data from a naming service or directory service and JDBC is used when you are querying / updating data in a Database server.


Difference between JDBC and JNDI

Connection conn = null;
try {
Class.forName ("com.mysql.jdbc.Driver", true, Thread.currentThread (). GetContextClassLoader ());
conn = DriverManager.getConnection ("jdbc: mysql :/ / MyDBServer? user = *** & password = ****");
.....
conn.close ();
}
catch (...) {...} finally {
the if (conn! = null) {
try {
conn.close ();
}
catch (...) {...}
}

Problems?
1, the database server name MyDBServer username and password may need to be modified, and consequent the JDBC URL repairs you want to modify;
2, the database may be the use of other products;
With the increase in the actual terminal, the original configuration of the connection pool parameters may need to be adjusted;

The solution database-level programmers do not have to care about things that only need to know how to refer to
The JNDI appear.
Define the data source, that is, JDBC reference parameters, set a name to the data source;
Data source name in the program by referencing the data source to access the database;

/ Jndi connection
Context initCtx = new InitialContext ();
Context envCtx = (Context) initCtx.lookup ("java: comp / env");
DataSource ds = (DataSource) envCtx.lookup ("jdbc / webtest");
conn = ds.getConnection (); 

/ / Jdbc connection
Class.forName ("com.mysql.jdbc.Driver", true, Thread.currentThread (). GetContextClassLoader ());
conn = DriverManager.getConnection ("jdbc: mysql :/ / localhost / mismain? user = root & autoReconnect = true");

Programmers to develop, you know you want to develop the application to access the MySQL database, so a reference to the MySQL JDBC driver class is encoded by using the appropriate JDBC URL to connect to the database.

Just like the following code:
Connection conn = null;
try ... {
Class.forName ("com.mysql.jdbc.Driver", true, Thread.currentThread (). GetContextClassLoader ());
conn = DriverManager.getConnection ("jdbc: mysql :/ / MyDBServer? user = qingfeng & password = mingyue");
......
conn.close ();
} Catch (Exception e) {
e.printStackTrace ();
} Finally ... {
the if (conn! = null) ... {
try ... {
conn.close ();
} Catch (SQLException e) ... {}
}
}

This is the traditional approach, but also the previously common practice of non-Java programmers (such as Delphi, VB, etc.). This approach generally does not produce in the small-scale development process, as long as the programmers familiar with the Java language, understand the technology and MySQL JDBC can quickly develop the appropriate application.
No JNDI approach the problems: 1, database server name MYDBSERVER, user name and password may need to be changed, which led to the JDBC URL need to be modified; 2, the database may switch to other products, such as switching to DB2 or Oracle, triggered JDBC driver package and class names need to be modified; 3, with the increase of the actual use of the terminal, the original configuration of the connection pool parameters may need to be adjusted; ...

Solution: the programmer should not need to care about what specific database background? JDBC driver? What is JDBC URL format? What is the user name and password to access the database? "And so these problems, programmers write the program should no references to the JDBC driver, server name, user name or password - not even database pool or connection management. But these issues to the J2EE container to configure and manage, the programmer need only reference to these configuration and management.
Thus, there is a JNDI.
JNDI approach: First, configure JNDI parameters, define a data source in a J2EE container, which is the the JDBC reference parameter set a name to the data source; reference data source, the data source name in the program to access the back-end database.
The specific operation is as follows (in JBoss as an example):
1, configure the data source in JBoss D :/ jboss420GA/docs/examples/jca file folder, there are a lot of different databases referenced data source definition template. Copy the mysql-ds.xml file to the server you're using, such as D to :/ jboss420GA/server/default/deploy.
Mysql-ds.xml file to modify the content, so to through JDBC correct access your MySQL database,
As follows:
Connection conn = null;
try ... {
Class.forName ("com.mysql.jdbc.Driver", true, Thread.currentThread (). GetContextClassLoader ());
conn = DriverManager.getConnection ("jdbc: mysql :/ / MyDBServer? user = qingfeng & password = mingyue");
......
conn.close ();
} Catch (Exception e) {
e.printStackTrace ();
} Finally ... {
the if (conn! = null) ... {
try ... {
conn.close ();
} Catch (SQLException e) ... {}
}
}
<? Xml version = "1.0" encoding = "UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name> MySqlDS </ jndi-name>
<connection-url> jdbc: mysql :/ / localhost: 3306/lw </ connection-url>
<driver-class> com.mysql.jdbc.Driver </ driver-class>
<user-name> root </ user-name>
<password> rootpassword </ password>
<exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter </ exception-sorter-class-name>
<metadata>
<type-mapping> mySQL </ type-mapping>
</ Metadata>
</ Local-tx-datasource>
</ Datasources>

Defined a the named MySqlDS data source, parameters include the URL of the JDBC driver class name, user name and password.
2 references in the program data source:
Connection conn = null; try ... {
Context ctx = new InitialContext ();
Object datasourceRef = ctx.lookup ("java: MySqlDS"); / / the Citation data source DataSource ds = (DataSource) DataSourceRef; the conn = to the ds.getConnection ();
......
c.close ();
} Catch (Exception e) {
e.printStackTrace ();
} Finally ... {
the if (conn! = null) ... {
try ... {
conn.close ();
} Catch (SQLException e) ... {}
}
}

Using JDBC directly or referenced by JNDI data source programming code is almost the same, but now the program can not care about the specific JDBC parameters.

After the deployment of the system, if the relevant parameters of the database changes, you only need to reconfigure mysql-ds.xml modify the JDBC parameters, as long as the name of the data source is the same, there is no need to modify the source code.

Thus, JNDI to avoid the tight coupling between the program and database to make the application easier to configure, easy to deploy.



JNDI Example for Servlet Web Application


Actual benefit of DataSource comes when we use it with a JNDI Context such as using 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 DataSource configuration details for Apache Tomcat servlet container.
Apache Tomcat provide three ways through which we can 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 need 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 even 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/confdirectory. 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 aResourceLink 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.
If you are getting bored with theory, well it’s over now and we will look into the implementation details now with a simple Servlet based web application.
JNDI Configuration for DataSource – server.xml
Add below code in the tomcat server.xml file. The code should be added in the GlobalNamingResourceselement. Also make sure that database driver is present in the tomcat lib directory, so in this case mysql jdbc jar needs 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.
Resource Link Configuration – context.xml
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 should use the name defined in the resource link in the program to get the resource.
Servlet DataSource JNDI Example
Create a dynamic web application with name JDBCDataSourceTomcat and then create a Servlet with below code.

    JDBCDataSourceExample.java

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, basically removing WebServlet annotation and configuring it in web.xml file.
The part of servlet code that we are interested in are;
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 that which database we are connected.
Now when you will run the application, you will see following output.

Let’s see how easy it is to switch the database server because we are using 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.

That’s all for JNDI configuration and usage in Tomcat, you can define the resource in similar way in context.xml files too.

Advance Java Blogging

Java New Articles

Javas Latest News

Java Web Services and XML

Ajax Latest News

Mac OS Java Features

Advance Spotlights

Patterns Features