Thursday, July 28, 2011

Connection Pooling Example in Java with MySQL, Oracle, DB


ConnectionPool.java

package com;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

public class ConnectionPool implements Runnable
{    
    // Number of initial connections to make.
    private int m_InitialConnectionCount = 5;    
    // A list of available connections for use.
    @SuppressWarnings("rawtypes")
private Vector m_AvailableConnections = new Vector();
    // A list of connections being used currently.
    @SuppressWarnings("rawtypes")
private Vector m_UsedConnections = new Vector();
    // The URL string used to connect to the database
    private String m_URLString = null;
    // The username used to connect to the database
    private String m_UserName = null;    
    // The password used to connect to the database
    private String m_Password = null;    
    // The cleanup thread
    private Thread m_CleanupThread = null;
       
                                             
    //Constructor
    @SuppressWarnings("unchecked")
public ConnectionPool(String urlString, String user, String passwd) throws SQLException
    {
        // Initialize the required parameters
        m_URLString = urlString;
        m_UserName = user;
        m_Password = passwd;

        for(int cnt=0; cnt<m_InitialConnectionCount; cnt++)
        {
            // Add a new connection to the available list.
            m_AvailableConnections.addElement(getConnection());
        }
       
        // Create the cleanup thread
        m_CleanupThread = new Thread(this);
        m_CleanupThread.start();
    }    
   
    private Connection getConnection() throws SQLException
    {
        return DriverManager.getConnection(m_URLString, m_UserName, m_Password);
    }
   
    @SuppressWarnings("unchecked")
public synchronized Connection checkout() throws SQLException
    {
        Connection newConnxn = null;
       
        if(m_AvailableConnections.size() == 0)
        {
            // Im out of connections. Create one more.
             newConnxn = getConnection();
            // Add this connection to the "Used" list.
             m_UsedConnections.addElement(newConnxn);
            // We dont have to do anything else since this is
            // a new connection.
        }
        else
        {
            // Connections exist !
            // Get a connection object
            newConnxn = (Connection)m_AvailableConnections.lastElement();
            // Remove it from the available list.
            m_AvailableConnections.removeElement(newConnxn);
            // Add it to the used list.
            m_UsedConnections.addElement(newConnxn);            
        }        
       
        // Either way, we should have a connection object now.
        return newConnxn;
    }
   

    @SuppressWarnings("unchecked")
public synchronized void checkin(Connection c)
    {
        if(c != null)
        {
            // Remove from used list.
            m_UsedConnections.removeElement(c);
            // Add to the available list
            m_AvailableConnections.addElement(c);        
        }
    }            
   
    public int availableCount()
    {
        return m_AvailableConnections.size();
    }
   
    public void run()
    {
        try
        {
            while(true)
            {
                synchronized(this)
                {
                    while(m_AvailableConnections.size() > m_InitialConnectionCount)
                    {
                        // Clean up extra available connections.
                        Connection c = (Connection)m_AvailableConnections.lastElement();
                        m_AvailableConnections.removeElement(c);
                       
                        // Close the connection to the database.
                        c.close();
                    }
                   
                    // Clean up is done
                }
               
                System.out.println("CLEANUP : Available Connections : " + availableCount());
               
                // Now sleep for 1 minute
                Thread.sleep(60000 * 1);
            }    
        }
        catch(SQLException sqle)
        {
            sqle.printStackTrace();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}


Main.java

package com;

import java.sql.*;


public class Main
{
    public static void main (String[] args)
    {    
        try
        {
        //JDBC Driver for MySql Database
           // Class.forName("com.mysql.jdbc.Driver").newInstance();
       
        //JDBC Driver for Oracle Database
        Class.forName("oracle.jdbc.OracleDriver");
        }
        catch (Exception E)
        {
            System.err.println("Unable to load driver.");
            E.printStackTrace();
        }

        try
        {        
            //Connection with MySQL Database....
        //ConnectionPool cp = new ConnectionPool("jdbc:mysql://localhost/test", "root", "vinay0809");
           
       //Connection with Oracle Database...
        ConnectionPool cp = new ConnectionPool("jdbc:oracle:thin:@localhost:1521:XE", "java", "vinay0809");
            Connection []connArr = new Connection[7];
       
            for(int i=0; i<connArr.length;i++)
            {
                connArr[i] = cp.checkout();
                System.out.println("Checking out..." + connArr[i]);
                System.out.println("Available Connections ... " + cp.availableCount());
            }                

            for(int i=0; i<connArr.length;i++)
            {
                cp.checkin(connArr[i]);
                System.out.println("Checked in..." + connArr[i]);
                System.out.println("Available Connections ... " + cp.availableCount());
            }
        }
        catch(SQLException sqle)
        {
            sqle.printStackTrace();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }        
    }
}




/**
 * @(#)DBConnect.java
 * @author
 * @version 1.00 2011/5/10
 */

import java.sql.*;

public class DBConnect
{
static Connection con=null;
static final String DBDriver="sun.jdbc.odbc.JdbcOdbcDriver";
static final String DBURL="jdbc:odbc:";
static final String DBName="JAVA";
static final String DBUser="";
static final String DBPassword="";

public Connection getConnection()
{
if(con !=null)
return con;
try
{
con=DriverManager.getConnection("jdbc:odbc:DB2DSN");
}
catch(SQLException e)
{
System.err.println("Cannot connect to database: for DB2. \n Check that DB2 is running and \nthe SKICLUB database Exists.");
}
return con;
}
/**
*main method
*@pram not used
*/
public static void main (String[] args)
{
DBConnect dbdemo=new DBConnect();
System.out.println("Getting Database Driver.");

try
{
Class.forName(DBDriver);
}
catch(ClassNotFoundException e)
{
System.err.println("Cannot load Database Driver:\n for DB2, your classpath muct include\nSQLLIB\\java12\\DB2Java.Zip.");
}
System.out.println("Getting Database Connection");
Connection con=dbdemo.getConnection();
if(con==null)
System.exit(0);
System.out.println("\nDatabase Ready.");
try
{
DatabaseMetaData md=con.getMetaData();
System.out.println("\nProduct Name: "+md.getDatabaseProductName());
System.out.println("\nDriver Name: "+md.getDriverName());
con.close();
}
catch(Exception e)
{
System.err.println(e.getClass().getName()+":"+e.getMessage());
}
}

}


Tuesday, September 7, 2010

JDBC, JNDI, CONNECTION POOLING

Mapping SQL Data to Java

One tricky subject that you need to be aware of when using JDBCs to access database is that data types in SQL don’t correspond exactly to Java Data Types. Indeed there are also significant variations between the SQL types supported by different database products. Even when different database support SQL types with the same semantics, they may give those types different names.
For Example:
Most of the major databases support a SQL data type for large binary values, but Oracle calls this type LONG RAW, Sybase calls it IMAGE, Informix calls it BYTE, and DB2 calls it LONG VARCHAR FOR BIT DATA.
JDBC defines a set of generic SQL type identifiers in the class java.sql.Types. These types have been designed to represent the most commonly used SQL types. While programing with the JDBC API, we have to use these JDBC types to reference generic SQL types, without having to concern yourself with the exact SQL type name used by the target database.
If we write portable JDBC program that can create tables on a variety of different databases, we will faced with two choices:
Ø  First, we can restrict our self to using only very widely accepted SQL type names such as INTEGER, FLOAT, or VARCHAR, which are likely to work for all databases.
Ø  Second, we can use the “java.sql.DatabaseMetaData.getTypeInfo()” method to discover which SQL types are actually supported by a given database, ad select a data-specific SQL type name that matches a given JDBC type.
The following table illustrates the general correspondence between Java data types and SQL types:
Java Type
Sql type
String
char, varchar, or longvarchar
java.math.Bigdecimal
numeric
boolean
bit
byte
tinyint
short
smallint
int
integer
long
bigint
float
real
double
double
byte[]
binary, varbinary, or longvarbinary
java.sql.Date
date
java.sql.Time
time
java.sql.Timestamp
timestamp
Clob
clob
Blob
blob
Array
array
Struct
struct
Ref
ref
Java class
java_object

Database Connection

The main classes and interface traditionally involved in making a connection to the database are:
Ø  The “java.sql.Driver” interfaceà Responds to connection requests from the DriverManager and provide information about its implementation.
Ø  The “java.sql.DriverManager” classà Maintains a list of Driver implementations.
Ø  The “java.sql.Connection” interfaceà Represents a single logical database connection.

There are two way of Driver loading. The Drivers are loaded by setting the jdbc.drivers system property or by using the “Class.forname()” method call.
The process of passing a driver name and the URL from obtaining a connection seems to be unnecessarily complex when we are trying to write database independent code. Details like registering driver should be abstracted away from the application, and this is made possible with the Java Naming and Directory interface (JNDI) and the JDBC Optional Package.

Java Naming and Directory Interface

The Java Naming and Directory interface (JNDI) is the Java API that allows us to access naming and directory services in the transparent way. The JNDI architecture consists of an API and a Service Provider Interface (SPI). Java applications use the JNDI API to access a variety of naming and directory services. The JNDI SPI enables a variety of naming and directory services to be plugged in transparently, thereby allowing the java application using the JNDI API to access their services.



The JNDI PI is divided into five Java Packages:
Ø  “javax.naming”
ü  The “javax.naming” package contains class and interfaces for accessing naming services. This package define a context interface, which is the core interface for looking up, binding/unbinding, renaming objects, and creating and destroying subcontexts. The most commonly used operation is
v  lookup() à It used to find the name of object we want to look up, and returns the object bounded to that name.

Ø  “javax.naming.directory”
ü  The “javax.naming.directory” package extends the “javax.naming” package to provide functionality for accessing directory services in addition to naming services.
ü  This package allows applications to retrieve attributes associated with objects stored in the directory and to search for objects using specified attributes. The commonly used method:
v  getAttributes() à It used to retrieve the attributes associated with a directory object.
v  modifyAttributes() à This method allowing to add, replace, and or modify attributes ad their variables

Ø  “javax.naming.event”
ü  The “javax.naming.event” package contains classes and interface for supporting event notification in naming and directory services.
Ø  “javax.naming.ldap”
ü  The “javax.naming.ldap” package contains class and interfaces for using features that are specific to LDAP that are not already covered by the more generic “javax.naming.directory” package.
ü  The most of JNDI find “javax.naming.directory” package sufficient at all, no need to use “javax.naming.ldap” package at all.
ü  The main purpose of using “javax.naming.ldap” package is primarily for those applications that need to use extended operations, controls, or unsolicited notification.
Ø  “java.naming.spi”
ü  The “java.naming.spi” package provides the means by which developers of different naming/directory service providers can develop and hook up their implementation so that the corresponding services are accessible from applications that use JNDI.
ü  This package allows different implementations to be plugged in  dynamically.
ü  These implementations include those for the initial context and for contexts that can be reached from the initial context.