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
Related
I have connection provider class as bleow to return connection.
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws ClassNotFoundException, SQLException {
try (Connection connection = DriverManager
.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
) {
return connection;
}
}
}
Here is main method to call connection provider.
public void Test() {
try {
Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
But "com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed." error are always show at below line of code.
PreparedStatement ps = con.prepareStatement("");
Because, according to Oracle documentation, If use try with resources java 7 features, resources are auto close after try block even it's errors occurred or not. So even I returned the connection it's already closed.
Let me know, my usage logic is wrong?
How can I return this connection inside try with resource?
I tried many time googling for solution but does not get convenience answers for me.
Let me know your suggestion and feedback please.
What you can't do...
With a try-with-resources as you have it after you return the connection you return(d) is close(d). You can't return the connection from inside the try with resources.
What you can do...
Pass the connection (inside your try-with-resources) to a method that takes a connection. You can also use a ConnectionPool, and get the Connection when you need it (to create and execute a query).
Let me know, my usage logic is wrong?
The usage of 'try-with-resources' logic is wrong in this context, because the intention of ConnectDB() is to return a connection instance which could be actually used by the caller to send a SQL statement, but instead, the connection instance is getting auto-closed, before it could be used by the caller, because of using 'try-with-resources' construct of Java.
Quick how-to on try-with-resource and JDBC
Your ConnectionProvider's ConnectDB already declares it is throwing SQLException - so no need to catch it in here: (You should consider replacing this code with connection pool maybe)
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
}
}
Instead use try-with-resource in your test-class to clean up your code and focus on errors your SQL code
might have:
public void Test() {
try (Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("SELECT 1")) {
//Prepare your Statement
ps.setInt(1, 1);
//And another try-with-resource for the result - note the closing brace
try(ResultSet rs = ps.executeQuery()) {
while(rs.next()) {
//Handle your Result
System.out.println(rs.getString(1));
}
} // This closes try-with-resource. Exception will be rethron to be caught in outer catch!
} catch (SQLException e) {
//SQL is Broken - but only ONE catch to catch them all
e.printStackTrace();
}
}
That way you gain
Better readability for your code (no calls to close surrounded by finally and if != null)
Centralized error handling if anything in your SQL code breaks (so you can focus on functional error of "statement didn't run")
Better code quality: No need to worry about Cursors, Statements, Connections not being propery closed.
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
I have a stateless session bean a method of which is used repetitively for running an SQL query within a plain JDBC connection. To avoid having to open and close connections too frequently, I came up with the following approach and wondering if it is a good practice:
I open the connection once in a method annotated #PostConstruct and close the connection in another method annotated #PreDestroy
The code works fine with no apparent memory leaks or any issues that I know of - just wondering if more experienced developers would agree if it is a good practice.
#PostConstruct
public void initBean() {
try {
conn = Connector.getConnection();
} catch (Exception e) {
// Handle errors for Class.forName
e.printStackTrace();
}
}
public String runTheQuery(String sql) {
String result ="";
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
result = rs.getString(1);
rs.close();
pstmt.close();
} catch (SQLException se) {
// Handle errors for JDBC
}
return result;
}
#PreDestroy
public void endingTitles() {
System.out.println("Closing the JDBC connection...");
try {
rs.close();
conn.close();
pstmt.close();
} catch (SQLException se) {
// Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (pstmt != null)
pstmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}// end finally try
}// end try
}
The best solution is to use DataSource
#Resource(mappedName="java:/DefaultDS")
DataSource dataSource;
public String runTheQuery(String sql) throws SQLException
Connection con = dataSource.getConnection();
try {
...
} finally {
con.close();
}
}
Data sources normally always have a minimum number of open connections, so in most cases there will be no real overhead getting a connection from a data source.
So it's only a valid practice, if you have measured before, and it it really solves an existing performance problem.
Otherwise it's not common, and therefore it's something like premature performance optimization.
Data sources offer additonal functionality: For example to check a connection, if it's still valid, before it gets injected. If you did it yourself, you would have to reimplement it. And there are possibly errors in that code.
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;
}
}
I have a Servlet which initializes its DataSource in the Servlets init method (because it is accessed there the first time). When the servlet is getting loaded I get the following exception message
Cannot create JDBC driver of class '' for connect URL 'null'
But when the first request is processed the jndi lookup works fine and the DataSource is initialized properly.
Here is my DataSource class:
public class PostgresDataSource{
private static DataSource dataSource;
static {
try {
dataSource = (DataSource) new InitialContext().lookup("java:/comp/env/jdbc/somedb");
} catch (NamingException e) {
Log.logger.fatal("Failed to initialize DB!");
Log.logger.error(e.getMessage());
e.printStackTrace();
}
}
public static Connection checkOut(){
if ( dataSource != null )
{
try {
return dataSource.getConnection();
} catch (SQLException e) {
Log.logger.error("Failed to establish DB connection!");
Log.logger.error(e.getMessage());
e.printStackTrace();
return null;
}
}
else
{
Log.logger.error("Failed to check out DB-Connection: Postgres DataSource not initialized!");
return null;
}
}
public static void checkIn( Connection dbcon){
if ( dataSource != null )
{
try {
dbcon.close();
} catch (SQLException e) {
Log.logger.error("Failed to close DB connection!");
e.printStackTrace();
}
}
else
{
Log.logger.error("Cannot check in DB-Connection: Postgres DataSource not initialized!");
}
}
}
Anyone encountered the same problem? What's the reason for this and how to solve it?
Instead of using
dataSource = (DataSource) new InitialContext().lookup("java:/comp/env/jdbc/somedb");
Please use the following, this may solve the problem
InitialContext context = new InitialContext();
Context envCtx = (Context) context.lookup("java:comp/env");
dataSource = (DataSource) envCtx.lookup("jdbc/somedb");