Sei sulla pagina 1di 11

Preparing a new Tomcat 6 project for DB Pooling with JDBC and JNDI

Prepare by Nico Coetzee on 31 May 2010

Licensed under the GNU Free Document License (http://www.gnu.org/copyleft/fdl.html)

Introduction
I have found very little comprehensive documentation all in one place describing how to start a new
project in NetBeans 6.8 with Tomcat 6 and DB Pooling. This document is therefore a quick step-by-
step HOWTO describing the process.

Requirements
This HOWTO was created based on tests in the following environment:
• Ubuntu 10.4 (Desktop)
• NetBeans 6.8 (including the built-in Tomcat server version 6.0.20)
• CentOS 5.5 64Bit As the DB server system

Other notable software versions:


• Java JDK : jdk1.6.0_18
• MySQL JDBC Driver : mysql-connector-java-5.1.12

It was tested against the following MySQL DB Server: 5.0.77 Source distribution

In addition, the document assumes “dbhost” to be a resolvable host name of the DB server.

The following DB permission were added:


mysql> grant select,insert,update on test.* to 'testuser'@'%' identified by 'password';
Query OK, 0 rows affected (0.01 sec)

mysql> flush privileges;


Query OK, 0 rows affected (0.01 sec)

mysql> show grants for 'testuser'@'%';


+--------------------------------------------------------------------------------+
| Grants for testuser@% |
+--------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'testuser'@'%' IDENTIFIED BY PASSWORD '5d2e19393cc5ef67' |
| GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'testuser'@'%' |
+--------------------------------------------------------------------------------+
2 rows in set (0.01 sec)
Step-by-Step Guide

Step 1 – Create a new Java Web Project


You can start this in the normal way:

1. Launch NetBeans if it's not already running


2. From the File menu, select “New Project”
3. Create a new “Web Application” (under the “Java Web” category)

Step 2 – Create a Context


With the project now open, navigate to the “Configuration files” and locate the “context.xml” file.
The contents of the file should look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/db_pooling_sample"/>

The “path” may be different in your project.

Next, add the database context. The file will now look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/db_pooling_sample">
<Resource name="jdbc/testdb"
auth="Container"
type="javax.sql.DataSource"
username="testuser"
password="password"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://dbhost:3306/test"
maxActive="8"
maxIdle="4"/>
</Context>
Step 3 – Add the new resource to the web.xml file
Still under the “Configuration files” you will notice a file called web.xml – open it as well.

Several TAB's are displayed. Navigate to the “XML” tab.

At the bottom, just above the closing “</web-app>” tag, add the new resource:
<resource-ref>
<description>DB Resource</description>
<res-ref-name>jdbc/testdb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Step 4 – Prepare some TEST data


This is purely for testing functionality. Log on to your DB server and create a test table. The
following was used in this document:
[root@localhost ~]# mysql -uroot test
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.0.77 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> create table `test1` ( `uid` int unsigned not null auto_increment primary key,
`create_date` timestamp, `data` varchar(255) null ) engine=myisam;
Query OK, 0 rows affected (0.03 sec)

mysql> insert into `test1` ( `data` ) values ( 'aaa' ), ( 'bbb' ), ( 'ccc' );


Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> select * from `test1`;


+-----+---------------------+------+
| uid | create_date | data |
+-----+---------------------+------+
| 1 | 2010-05-31 12:22:37 | aaa |
| 2 | 2010-05-31 12:22:37 | bbb |
| 3 | 2010-05-31 12:22:37 | ccc |
+-----+---------------------+------+
3 rows in set (0.00 sec)
Step 5 – Add the MySQL JDBC Drivers
In NetBeans, locate the “Libraries” under the “Projects” TAB of your current project.

Right click on “Libraries” and select “Add JAR/Folder...”

Navigate to your MySQL JDBC JAR file and select it (mysql-connector-java-5.1.12-bin.jar)

The project should now BUILD correctly (SHIFT+F11). If there are errors at this point, first
address them and ensure there are no build errors before proceeding.

Step 6 – Create a Test Queries Class


You can easily test by creating a test class for DB connection and accompanying test Servlet.

Note: I prefer not to call the DB directly from the Servlet but keep the DB functions in a separate
class. Your implementation may be slightly different.

You must also change the package name to suite your environment. I have used “dbtesting” as the
package name.

1. On “Source Packages”, right click and select “New → Java Package”. Set the name to
“dbtesting”
2. Again in “Source Packages”, on the newly created “dbtesting” package, right click and
select “New → Java Class”. Select “DBtesting” as the name.
Please look at the appendix for the full source of this new class (file DBtesting.java)

Step 7 – Create a test Servlet


This will be for testing the DBtesting class functions created in step 6.

1. On the “dbtesting” package, right click and select “New → Servlet”


2. Set the name (“landingTestDB” for example)

Please look at the appendix for the full source of this new Servlet (file landingTestDB.java)

And now you are ready to TEST :-) Point your browser to
http://localhost:8084/db_pooling_sample/landingTestDB
Conclusion
This should get you up and going quickly enough. Just a couple of final thoughts:

1. All you DB connections still require a disconnect call. It's crucial to disconnect before
returning from a method. Have a close look at the sample code how I did it – and I do not
claim this to the most correct way. If you have a better way, please let me know!!
2. Security was IGNORED in this quick HOWTO. You have to check your input data and also
do safer inserts. SQL Injection attacks are VERY LIKELY if you use the example as is on
a production system.
Appendix A – Source Code

Source: DBtesting.java
package dbtesting;

// Used for DB functions (Pooling)


import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

// Other required imports


import java.util.List;
import java.util.ArrayList;

/**
*
* @author Nico Coetzee
*/
public class DBtesting {

private DataSource ds;


private Connection con;

/**
* CONSTRUCTOR
*/
public DBtesting(){
try{
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/testdb");
dbConnect();
} catch( Exception e ){
e.printStackTrace();
}
}

/**
* Establish a connection to the datasource
*/
private void dbConnect(){
try {
con = ds.getConnection();
} catch( Exception e ){
e.printStackTrace();
}
}

/**
* Disconnect from the data source
*/
public void dbDisconnect() {
try {
con.close();
} catch ( Exception e ){
e.printStackTrace();
}
}

/**
* Run a SELECT type query where you expect an answer
* @param sqlQuery The SQL query to execute
* @return ResultSet
*/
private ResultSet runSelectQuerie( String sqlQuery ){
try{
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
return stmt.executeQuery( sqlQuery );
} catch ( Exception e ) {
e.printStackTrace();
}
return null;
}

/**
* Run a UPDATE type query
* @param sqlQuery The SQL query to execute
* @return Boolean (false on exception)
*/
private boolean runUpdateQuerie( String sqlQuery ){
try{
Statement stmt = con.createStatement();
stmt.executeUpdate( sqlQuery );
return true;
} catch ( Exception e ) {
e.printStackTrace();
return false;
}
}

////////////////////////////////////////
// //
// DB Functions //
// //
////////////////////////////////////////

/**
* Add data to our test table
* @param data String containing data
* @return boolean true is succesful, else false
*/
public boolean runAddData( String data, boolean dbdisconnect ){
try{
return runUpdateQuerie( "insert into `test1` ( `data` ) values ( '"
+ data + "' )" );
} catch( Exception e ){
e.printStackTrace();
}
if( dbdisconnect == true ){
dbDisconnect();
}
return false;
}

/**
* OVERIDE to automatically disconnect after the function was run
*/
public boolean runAddData( String data ){
return runAddData( data, true );
}

/**
* Get all data from our test table
* @return List of rows, each containing a "|" seperated list of fields
*/
public List runGetData( boolean dbdisconnect ){
List dataList = new ArrayList();
try{
ResultSet rs = runSelectQuerie( "select
`uid`,`create_date`,`data` from `test1`" );
while(rs.next()){
//retVal = rs.getString( "value" );
String s = rs.getString( "uid" ) + "|" + rs.getString(
"create_date" )+ "|" + rs.getString( "data" );
if( s.length() > 0 ){
dataList.add(s);
}
}
} catch( Exception e ){
e.printStackTrace();
}
if( dbdisconnect == true ){
dbDisconnect();
}
return dataList;
}

/**
* OVERRIDE to automatically disconnect after the function was run
*/
public List runGetData(){
return runGetData( true );
}

}
Source: landingTestDB.java
package dbtesting;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// Additional required imports


import java.util.List;

/**
*
* @author Nico Coetzee
*/
public class landingTestDB extends HttpServlet {

private String html_header = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML


4.01 Transitional//EN\"
\"http://www.w3.org/TR/html4/loose.dtd\"><html><head><title>Db Pooling
Tests</title><meta name=\"AUTHOR\" content=\"Nico Coetzee\"><meta http-
equiv=\"Content-Type\" content=\"text/html; charset=utf-
8\"></head><body><p><FORM action=\"/db_pooling_sample/landingTestDB\"
method=\"POST\">Add data: <INPUT type=\"text\" name=\"data\"><INPUT
type=\"submit\"></FORM></p><hr><h3>Current Data</h3><p><TABLE width=\"600\"
cellspacing=\"2\" border=\"1\" cellpadding=\"2\" align=\"center\"><TR
bgcolor=\"lightGray\"><TD width=\"50\">#</TD><TD width=\"200\">Create
Date</TD><td>Data</td></TR>";
private String html_row_tmpl = "<tr><td><div
align=\"center\">_NUM_</div></td><td><div
align=\"center\">_CREATE_DATE_</div></td><td><div
align=\"center\">_DATA_</div></td></tr>";
private String html_footer = "</TABLE></p></body></html>";
private String html_error =
"<html><head><title>Error</title></head><body><h3>Error</h3><hr><pre>_ERROR_MSG
_</pre></body></html>";

/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code>
methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

String html = "";


try{
processDataPost( request );
html = html_header + getData() + html_footer;
} catch( Exception e ){
html = html_error;
html = html.replace( "_ERROR_MSG_",
e.getMessage().toString() );
}

try {
out.println( html );
} finally {
out.close();
}
}

/**
* If data was submitted, add it to the database
* @param request HttpServletRequest object
*/
private void processDataPost( HttpServletRequest request ){
try{
DBtesting db = new DBtesting();
if( request.getParameter("data").length() > 0 ){
db.runAddData( request.getParameter("data") );
}
} catch( Exception e){
e.printStackTrace();
}
}

/**
* Get the data from the DB and construct the table rows
* @return
*/
private String getData(){
String strRows = "";
try{
DBtesting db = new DBtesting();
List dbrows = db.runGetData();
if( dbrows.size() > 0 ){
for (int i = 0; i < dbrows.size(); i++) {
strRows = strRows + constructTblRow(
dbrows.get(i).toString() );
}
return strRows;
}
} catch( Exception e ){
e.printStackTrace();
}
return "<tr><TD colspan=\"3\"><div align=\"left\"><em>No
data</em></div></TD></tr>";
}

/**
* Build the HTML row containing the data.
* @param s String with "|" seperated list of fields
* @return String with HTML
*/
private String constructTblRow( String s ){
String[] fields = s.split("\\|");
String tmpRow = html_row_tmpl;
tmpRow = tmpRow.replace("_NUM_", fields[0] );
tmpRow = tmpRow.replace("_CREATE_DATE_", fields[1] );
tmpRow = tmpRow.replace("_DATA_", fields[2] );
return tmpRow;
}

// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click


on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Returns a short description of the servlet.
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>

Potrebbero piacerti anche