Best structure for connection pooling with Java EE - java

I am trying to figure out the best structure for connection pools so that I can access the connection pool from any servlet and establish a connection to my database. I have been following some tutorials in setting up and configuring the datasource and connection pool and they all have them initialized and accessed in classes that extend HttpServlet. So it looks something like this:
public class DatabaseConnector extends HttpServlet {
private static final long serialVersionUID = 1L;
private DataSource dataSource;
private Connection connection;
private Statement statement;
public void init() throws ServletException {
try {
// Get DataSource
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/test");
} catch (NamingException e) {
e.printStackTrace();
}
}
/**
* #see HttpServlet#HttpServlet()
*/
public DatabaseConnector() {
super();
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ResultSet resultSet = null;
try {
// Get Connection and Statement
connection = dataSource.getConnection();
statement = connection.createStatement();
String query = "SELECT * FROM STUDENT";
resultSet = statement.executeQuery(query);
while (resultSet.next()) {
System.out.println(resultSet.getString(1) + resultSet.getString(2) + resultSet.getString(3));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (resultSet != null) {resultSet.close();}
if (statement != null) {statement.close();}
if (connection != null) {connection.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
It looks like to me that this connection pool is only for this servlet which would only distribute connections when a get request is sent the this servlets URL. What if I want to have another servlet that needs to access the database. I was thinking of just removing the doGet and doPost methods in this servlet and leave the init so that the connection pool would be initialized at runtime, and then have a singleton reference to this servlet which could be used in other servlets. However, this doesn't seem like the right way to me. What is the best way to structure a connection pool that can be accessed from all servlets and listeners?
Thanks for your help!

Completely wrong.
The correct way to access a connection is to use a JNDI connection pool.
Servlets are HTTP listeners. They shouldn't have anything to do with databases.
A properly layered Java EE solution will restrict data sources to the service tier. It will check connections in and out, know about units of work and transactions, and interact with data access objects.
Servlets should deal with services, not data sources.

The logic to create a connection could be placed within a simple class.
public class ConnectionManager{
public static Connection getConnection(){
Connection connection = null;
try {
// Get DataSource
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/test");
connection = dataSource.getConnection();
} catch (NamingException e) {
e.printStackTrace();
}
if(connection == null){
throw new RuntimeException("Cannot connect");
}
return connection;
}
}

Related

The correct way to get/close DataSource connection

I am developing a dynamic web project on eclipse.
Below is an example of connecting MySQL using DataSource.
Is it the correct way? I mean is it normal to get connection in a Servlet?
Moreover, I find this way to get/close connection is tedious because I need to write exact same part of codes every time when I want to get/close connection. I think there should be a better way. Could someone give me some suggestions?
Thank you!
#WebServlet(name="HelloUser", urlPatterns={"/hellouser"})
public class HelloUserServlet extends HttpServlet{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
DataSource ds = MyDataSourceFactory.getMySQLDataSource();
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery(...);
...
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
Starting from Java 7 you can use try-with-resource( JDBC api is updated to implement Autocloseable) .
The try-with-resources statement is a try statement that declares one
or more resources. A resource is an object that must be closed after
the program is finished with it
E.g.
try (Connection con = ds.getConnection();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(...)) {...}

java servlet how to get value from init() method and use them outside the method?

Help please I'm new on servlet
I'm trying to initialize value on the init method and use them after
but I get nullpointerexception
this is my classe Hello it contains 2 methods init() and jdbcinfo()
i need to get data base connection once
package com.Ws;
//imports..
public class Hello extends HttpServlet {
public static Connection con;
#Override
public void init() throws ServletException
{
try {
Class.forName("net.sourceforge.jtds.jdbc.Driver");
con =DriverManager.getConnection("jdbc:jtds:sqlserver://localhost:6543/Dbname","user","");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("--printStackTrace--"+e);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("--printStackTrace2--"+e);
}
}
}
//I get nullpointerexception here con = null
public String jdbcInfo(String req) {
PreparedStatement statementT;
try {
connection =con;
PreparedStatement statement = connection.prepareStatement(req);
ResultSet result = statement.executeQuery();
while (result.next()) {
///
}
}
catch (Exception e) {
e.printStackTrace();
System.out.println("exception: Serveur base de donnée indosponnible");
}
if (res == "1")
return res;
else
return "false";
}
}
my web.xml
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>com.Ws.Hello</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
#geert3 is correct. You do not want to create a connection and save it in a field in a servlet's init() method. Servlets are singletonscan handle requests from multiple threads, so all fields should reference objects that are deeply immutable and thread-safe. Connection objects are niether.
Instead, you should use a database connection pool. Don't build your own connection pool code; there are many choices out there. If you are running the code inside an application server, your application server might have built-in database pool support.
As for the particular problem with the code, the best way to trouble-shoot it is to look at the printed stack trace.
//I get nullpointerexception here con = null
Your Instance variable of Class Connection con can be null if it didn't get initialized . Now how can this be possible :
At this line
Class.forName("net.sourceforge.jtds.jdbc.Driver");
if jar file is not present in your class Path this line will throw ClassNotFoundException and in that case it comes out of try block without executing this line
con =DriverManager.getConnection("jdbc:jtds:sqlserver://localhost:6543/Dbname","user","");
and in this case your con will be null
So Just check if the jar file is actually present in your class path or not

servlet page shows blank when accessed later

I have a strange issue with servlet page. I have simple web application which contains just a servlet.I deployed it in Tomcat 7. When user enters url, the servlet should get directly executed, get the data from the database and print the output. But it shows blank page after some time. When I undeploy and deploy, it shows data. After some time when I access the page, it shows blank page. Then again when I redeploy, it shows data. Can someone please let me know how to resolve this? I have no clue why it happens. Below is my code.
I am using mysql database.mysql-connector-java-5.1.29-bin.jar added in lib folder and added to buildpath.
public class Homeservlet extends HttpServlet {
private static final long serialVersionUID = 1L;
static final String mysqldblink = "************";
static final String mysqlUsername = "username";
static final String mysqlPassword = "pw";
Connection connection =null;
Statement stmt = null;
/**
* #see HttpServlet#HttpServlet()
*/
public Homeservlet() {
super();
// TODO Auto-generated constructor stub
}
public void init(ServletConfig config) throws ServletException
{
super.init(config);
try{
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(mysqldblink,
mysqlUsername, mysqlPassword);
stmt = connection.createStatement();
}
catch(Exception E)
{
E.printStackTrace();
}
}
#Override
public void service(ServletRequest request, ServletResponse response)
{
PrintWriter pw = null;
try {
String query = "querytogetdata";
pw = response.getWriter();
ResultSet rs = stmt.executeQuery(query);
while(rs.next())
{
pw.println(rs.getString(1));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(Exception e)
{
e.printStackTrace();
}finally{
try{
pw.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
}
#Override
public void destroy( ) {
// Close the connection
try {
if (connection != null)
connection.close( );
if(stmt != null)
stmt.close();
} catch (SQLException ignore) { }
}
}

Pool empty. Unable to fetch a connection in 10 seconds

After some time of running I'm getting this error when I stress test my servlet with at least 20 browser tabs simultaneously accessing the servlet:
java.sql.SQLException: [tomcat-http--10] Timeout: Pool empty. Unable to fetch a connection in 10 seconds, none available[size:200; busy:200; idle:0; lastwait:10000].
Here is the XML config for this:
<Resource name="jdbc/MyAppHrd"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
testWhileIdle="true"
testOnBorrow="true"
testOnReturn="false"
validationQuery="SELECT 1"
validationInterval="30000"
timeBetweenEvictionRunsMillis="30000"
maxActive="200"
minIdle="10"
maxWait="10000"
initialSize="200"
removeAbandonedTimeout="120"
removeAbandoned="true"
logAbandoned="false"
minEvictableIdleTimeMillis="30000"
jmxEnabled="true"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
username="sa"
password="password"
driverClassName="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sqlserver://192.168.114.130/MyApp"/>
What could be the problem?
Update:
Java Code:
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Log LOGGER = LogFactory.getLog(MyServlet.class);
private void doRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
CallableStatement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
conn = getConnection();
stmt = conn.prepareCall("{call sp_SomeSPP(?)}");
stmt.setLong(1, getId());
rs = stmt.executeQuery();
// set mime type
while (rs.next()) {
if (rs.getInt(1)==someValue()) {
doStuff();
break;
}
}
stmt = conn.prepareCall("{call sp_SomeSP(?)}");
stmt.setLong(1, getId());
rs = stmt.executeQuery();
if (rs.next()) {
// do stuff
}
RequestDispatcher rd = getServletContext().getRequestDispatcher("/SomeJSP.jsp");
rd.forward(request, response);
return;
} catch (NamingException e) {
LOGGER.error("Database connection lookup failed", e);
} catch (SQLException e) {
LOGGER.error("Query failed", e);
} catch (IllegalStateException e) {
LOGGER.error("View failed", e);
} finally {
try {
if (rs!=null && !rs.isClosed()) {
rs.close();
}
} catch (NullPointerException e) {
LOGGER.error("Result set closing failed", e);
} catch (SQLException e) {
LOGGER.error("Result set closing failed", e);
}
try {
if (stmt!=null) stmt.close();
} catch (NullPointerException e) {
LOGGER.error("Statement closing failed", e);
} catch (SQLException e) {
LOGGER.error("Statement closing failed", e);
}
try {
if (conn != null){
conn.close();
conn = null;
}
} catch (NullPointerException e) {
LOGGER.error("Database connection closing failed", e);
} catch (SQLException e) {
LOGGER.error("Database connection closing failed", e);
}
}
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doRequest(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doRequest(request, response);
}
protected static Connection getConnection() throws NamingException, SQLException {
InitialContext cxt = new InitialContext();
String jndiName = "java:/comp/env/jdbc/MyDBHrd";
ConnectionPoolDataSource dataSource = (ConnectionPoolDataSource) cxt.lookup(jndiName);
PooledConnection pooledConnection = dataSource.getPooledConnection();
Connection conn = pooledConnection.getConnection();
return conn; // Obtain connection from pool
}
I suggest you change your getConnection method to the following you might actually be removing the Pooling support by going directly to via the javax.sql.PooledConnection interface
InitialContext cxt = new InitialContext();
String jndiName = "java:/comp/env/jdbc/MyDBHrd";
DataSource dataSource = (DataSource) cxt.lookup(jndiName);
return dataSource.getConnection();
Also use something like DBUtils#closeQuietly to clean up your connections
Update: You are removing the Pooling support from the Connection. If you run the following and look at the output you will see the connection retrieved directly from the DataSource is a ProxyConnection wrapping a PooledConnection.
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.put("username", "sa");
properties.put("password", "password");
properties.put("driverClassName", "net.sourceforge.jtds.jdbc.Driver");
properties.put("url", "jdbc:jtds:sqlserver://192.168.114.130/MyApp");
DataSourceFactory dsFactory = new DataSourceFactory();
DataSource ds = dsFactory.createDataSource(properties);
ConnectionPoolDataSource cpds = (ConnectionPoolDataSource) ds;
PooledConnection pooledConnection = cpds.getPooledConnection();
System.out.println("Pooled Connection - [" + ds.getConnection() + "]"); // Close will return to the Pool
System.out.println("Internal Connection - [" + pooledConnection.getConnection() + "]"); // Close will just close the connection and not return to pool
}
Probably, you are holding connection for too long.
Make sure that you do not open DB connection when you start processing request and then release it when you finally committed the response.
Typical mistake is:
#Override
protected void doGet (
final HttpServletRequest request,
final HttpServletResponse response
) throws
ServletException,
IOException
{
Connection conn = myGetConnection( );
try
{
...
// some request handling
}
finally
{
conn.close( )
}
}
In this code, database connection lifetime is totally at the mercy of the client connected to your server.
Better pattern would be
#Override
protected void doGet (
final HttpServletRequest request,
final HttpServletResponse response
) throws
ServletException,
IOException
{
// some request preprocessing
MyProcessedRequest parsedInputFromRequest =
getInputFromRequest( request );
final MyModel model;
{
// Model generation
Connection conn = myGetConnection( );
try
{
model = new MyModel( conn, parsedInputFromRequest );
}
finally
{
conn.close( );
}
}
generateResponse( response, model );
}
Note, that if the bottleneck is in model generation, you still going to run out of connections, but this is now a problem for DBA, that relates to better data management/indexing on the database side.
Check your jdbc connections are closed after completion of process. It may caused by unclosed connections.
Close your connection before the following.
RequestDispatcher rd = getServletContext().getRequestDispatcher("/SomeJSP.jsp");
rd.forward(request, response);
return;
Also remove return if it is not required.
The code you currently provide looks long/complex, but fine.
However, I guess your "doStuff" method might be a candidate for leaking more connections
First, you are not closing your Statement and ResultSet objects within the body of your method.
They should be cleaned-up when you call close on the the Connection (according to the JDBC spec), but in a pooled setting, they might not actually get cleaned up.
Second, you are unwrapping the pooled connection and returning the underlying connection which will break everything.
So, modify your code to be like this:
try {
conn = getConnection();
stmt = conn.prepareCall("{call sp_SomeSPP(?)}");
stmt.setLong(1, getId());
rs = stmt.executeQuery();
// set mime type
while (rs.next()) {
if (rs.getInt(1)==someValue()) {
doStuff();
break;
}
}
// ADD THESE LINES
rs.close(); rs = null;
stmt.close(); stmt = null;
stmt = conn.prepareCall("{call sp_SomeSP(?)}");
stmt.setLong(1, getId());
rs = stmt.executeQuery();
if (rs.next()) {
// do stuff
}
}
....
protected static Connection getConnection() throws NamingException, SQLException {
InitialContext cxt = new InitialContext();
String jndiName = "java:/comp/env/jdbc/MyDBHrd";
DataSource dataSource = (DataSource) cxt.lookup(jndiName);
return dataSource.getPooledConnection();
}
And, as others have said, you definitely want to clean-up your resources before you do things like forwarding to another page. Otherwise, you keep the connection far longer than necessary. It's a critical resource: treat it like one.

Where to initialize Connection Pooling, java tomcat

I have read this page: http://www.javaranch.com/journal/200601/JDBCConnectionPooling.html
The approach of Method Scope Connections seems quite good for me.
But i have one Question, when do i init the JDBCServlet class?
Every time i want a connection? Because i thought that everytime i want a connection i just call getConnection()...
public class JDBCServlet extends HttpServlet {
private DataSource datasource;
public void init(ServletConfig config) throws ServletException {
try {
// Look up the JNDI data source only once at init time
Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
datasource = (DataSource) envCtx.lookup("jdbc/MyDataSource");
}
catch (NamingException e) {
e.printStackTrace();
}
}
private Connection getConnection() throws SQLException {
return datasource.getConnection();
}
public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException {
Connection connection=null;
try {
connection = getConnection();
..<do JDBC work>..
}
catch (SQLException sqlException) {
sqlException.printStackTrace();
}
finally {
if (connection != null)
try {connection.close();} catch (SQLException e) {}
}
}
}
}
The JDBCServlet servlet is invoked when you navigate to a link where the servlet is mapped to.
So you dont have to do anything apart apart from the mapping from URL to servlet which is done in the web.xml.
the web container then create the instance of the servlet by using init method and then call doGet.
This is a PDF for a servlet tutorial with tomcat, but the basics are the same.
http://www.tutorialspoint.com/servlets/servlets_tutorial.pdf
look at the servlet deployment section
for the DBUtil Class this is a good example.
public class DBUtil {
private static DataSource dataSource;
static {
try {
dataSource = new InitialContext().lookup("jdbc/MyDataSource");
} catch (NamingException e) {
throw new ExceptionInInitializerError("'jdbc/MyDataSource' not found in JNDI", e);
}
}
public static Connection getConnection() {
return dataSource.getConnection();
}
}
This gives your class that can be used by all servlets in your Web Application.
you wil call the DBUtil class by
try {
connection = DBUtil.getConnection();
statement = connection.prepareStatement("SELECT id, foo, bar FROM table");
resultSet = statement.executeQuery();
//Do what you need to do.
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
Servlets are initialised by the Container which will call init as required and defined by the web.xml configuration file.
Use the Apache Tomcat JDBC Connection pools which does the same in a standard way.
There's many connection pooling libraries including MySQL's own. Many people use C3P0 which is very mature.
The common idea is that you define the Datasource in the server container and access the JNDI reference from your code. During the servlet init you're just looking up the datasource so this is the ideal place to do this. This will not use any connections until you actually perform an action.
See Tomcat DBCP for a good intro and if you wish to use C3P0 C3P0 Tomcat Configuration

Categories