MJDBC: a freeware package to optimize JDBC access in a Multithread environment
MJDBC is a package that i developed to increase the performance reached
by JDBC in a multithread environment. Just to remember, JDBC is the standard
Java API to access databases and Java is supposed to bring us the
ability to "write once, compile one, run anywhere". JDBC is coherent with
this philosophy: in fact it is an abstraction that allows the programmer
to interact with any database without knowing its own programming interface.
A good guide to JDBC programming is available here.
Without going deeply in JDBC programming let me cite a classic JDBC piece
of code. You can trace four different operations:
-
Loading JDBC driver to access the given database. This is accomplished
loading for name driver's class.
-
Opening JDBC connection, using DriverManager class
-
Submitting SQL query, using the Statement class
-
Closing JDBC connection
import java.sql.*;
public class App{
public static void main (String args[]) {
String url = "jdbc:subprotocol:db";
// load JDBC driver for my Database
try {
Class.forName("jdbcDriver");
} catch(Exception e){
System.out.println("Failed to load given jdbc Driver");
}
try {
// connect DB as specifed in the url, as user gulli and pwd gulli
Connection con = DriverManager.getConnection(url, "gulli", "gulli");
Statement select = con.createStatement();
ResultSet result = select.executeQuery("SELECT key, val FROM db_test");
// get the results for the yet submitted query
while (result.next()){
int key = result.getInt(1);
String val = result.getString(2);
System.out.println("key = " + key + "/nval = " + val);
}
// close connection and statement
select.close();
con.close();
} catch (Exception e){
e.printStackTrace();
}
}
}
This four step interaction is not very efficient, if there are many SQL
operations to be accomplished from time to time. For example in servlets
paradigm, each incoming HTTP request directed to a
servlet is handled by a separate thread that performs the above four step
interaction with the available database.
A good guide to servlet is available here.
Let me do a little summarization. Remember that servlets are standard API
to extend HTTP server functionality:
-
The first time a servlet is loaded in HTTP server, it executes a "public
void init(ServletConfig config)" method that allows the initialization
of servlet' status (single thread operation).
-
When a servlet is invoked through a specific HTTP client request, a new
thread is spawned and the method public void "doGet(HttpServletRequest
req, HttpServletResponse res)" is executed.
-
When the servlet is discarded from HTTP server (for example for off line
operation) the method "public void destroy()" is executed
to clean status (single thread operation).
So, servlets are cool !. Unlike cgi-bin, servlets have a good abstraction
to maintain their status without using external pattern of memory (like
files or so on..). Besides, servlets works in a real multi-thread environment.
And they have a transparent way to maintain client status from connections
through connections (but this is another story and it is out of the scope
of MJDBC).
Having in mind the servlets model, the solution the reduce latency of
answer of a database accessed via JDBC, is to minimize the need to load
the JDBC driver and to open and close connections to the database.
In MJDBC terminology a connection is thought as a shared object. It is
opened once and it is accessed by a set of concurrent threads in mutex
way. MJDBC acts as a connection manager: before submitting SQL statements,
every thread T asks for an non used
connection among the opened ones. After retrieving results T
informs MJDBC that the assigned connection is no more used
and it is available for later requests. Using servlets, all the connections
are opened during the execution of the "public void init(ServletConfig
config)" method and all the connections are closed during the execution
of the "public void destroy()method".
In order to better understand MJDBC let me show a little piece of a
servlet that use it. In this example i use postgresql
as database and Petet T Mount
as JDBC driver
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
// to gain benefits of having a pool of connections used in mutex
// manner and never closed until the destroy() of the servlet
import com.studioitech.gulli.MJDBC.*;
public class adserver extends HttpServlet{
// Statics
final static String JDBC_DriverName =
"postgresql.Driver";
final static String url = "jdbc:postgresql:ad";
final static String usr = "test";
final static String pwd = "test";
final static int connection = 2;
//MJDBC arbiter
dbArbiterConnections arbiter;
// arbiter to get available con
// Init method, loaded in single thread
mode by HTTP server
public void init(ServletConfig config)
throws ServletException
{
super.init(config);
try {
// Load arbiter to get available
connections
arbiter = new dbArbiterConnections(JDBC_DriverName,
url,
usr, pwd, connection);
} catch (Exception e1){
E.debug("Problems
initing arbiter " + e1.toString(), 0);
}
E.debug("Initing done", 0);
}
// doGet Method - method that runs when the servlet
is hit via GET
public void doGet(HttpServletRequest req, HttpServletResponse
res)
throws ServletException, IOException
{
PrintWriter out;
res.setContentType("text/html");
out = res.getWriter ();
E.setOutput(out);
// set output channel
E.flush();
// flush the acquired buffer, if any
E.setAutoFlush(true);// now set
autoflush
// A connection in the pool
dbConnection conInPool;
// get what i have to serve I can
specify a MIME TYPE
// or a KEY1 [KEY2], [KEY3] I must
specify a DIM
E.debug("Getting a request", 1);
String type = req.getParameter("type");
String dim = req.getParameter("dim");
String key1 = req.getParameter("key1");
String key2 = req.getParameter("key2");
String key3 = req.getParameter("key3");
E.debug("type=" + type + " dim="
+ dim + " key1=" + key1 +
" key2=" + key2 + "
key3=" + key3, 3);
try{
// Ask MJDBC to give
you a connection
conInPool = arbiter.getAnAvailableCon();
SQLwork sw = new SQLwork(conInPool.st,
out);
sw.doWork(type, dim, key1,
key2, key3);
// Tell MJDBC this connection
is available
conInPool.freeConnection();
} catch (Exception e){
E.debug("Got Exception: "
+ e.toString(), 0);
}
}
// here goes all de-initialization
public void destroy()
{
try {
// Shutdown MJDBC
arbiter.shutdown();
} catch(SQLException sqle)
{
}
}
}
You can notice that during the init phase of the servlet i create an
object arbiter istantiating the class dbArbiterConnection. I pass
to the constructor the name of the JDBC driver, the database url to connect
to, the user and its pwd, the number of connection to open with underlying
database.
arbiter = new dbArbiterConnections(JDBC_DriverName, url, usr,
pwd, connection);
The core of MJDBC using is exploited during multithread execution of
public void doGet(HttpServletRequest req, HttpServletResponse res)
method. For each incoming request to servlet i perform something like this:
// Ask MJDBC to give you a connection
conInPool = arbiter.getAnAvailableCon();
SQLwork sw = new SQLwork(conInPool.st, out);
sw.doWork(type, dim, key1, key2, key3);
// Tell MJDBC this connection is available
conInPool.freeConnection();
First at all, i ask the arbiter to give me an available MJDBC connection
and, if none is available the arbiter simple waits for one to became free
to be used. A MJDBC could be thought as a couple composed by a [JDBC
Connection, JDBC statement]. Then i use this connection to perform my SQL
work (SQLwork is just a class that in this example masquerades my raw SQL
query). Finally i free the yet used MJDBC connection. The cool thing here
is that the connection is not closed but just is become ready for another
use by a concurrent thread.
As you can see, using MJDBC is very simple and it is coherent with multithread
servlet environment and its idea of HTTP server's status maintained from
connection to connection. To conclude just few links:
|