I am facing following exception:
com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception: ** BEGIN NESTED EXCEPTION ** java.io.EOFException.
After specifying following pool-properties for the datasource, its able to auto-reconnect on connection-time-out; but the dead connections are existing in the pool are being reused and not being killed/evicted (ie. the validation-query and eviction parameters are not working). Following is my code. Can anyone please suggest some solution how to handle this?
public class DbConnection {
static DataSource datasource = new org.apache.tomcat.jdbc.pool.DataSource();
public static Connection getConnection() {
PoolProperties p = new PoolProperties();
p.setUrl("jdbc:mysql://192.168.0.9:3306/oet_v3?autoReconnect=true");
p.setDriverClassName("com.mysql.jdbc.Driver");
p.setUsername("root");
p.setPassword("napster123");
p.setJmxEnabled(true);
p.setTestWhileIdle(true);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(true);
p.setValidationInterval(20000);
p.setTimeBetweenEvictionRunsMillis(3000);
p.setMaxActive(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setMinEvictableIdleTimeMillis(3000);
p.setMinIdle(10);
Connection con = null;
try {
Context ctx = new InitialContext();
((DataSourceProxy) datasource).setPoolProperties(p);
con = datasource.getConnection();
Statement st1 = con.createStatement();
ResultSet rs1 = st1.executeQuery("select * from User_Login limit 0,1");
if (rs1.next()) {
System.out.println("LIVE CONNECTION********con: " + con + " rs.next=" + rs1.next());
} else {
System.out.println("&&&&&rs is null so secnd conn: " + con);
DataSource datasource1 = new org.apache.tomcat.jdbc.pool.DataSource();
((DataSourceProxy) datasource1).setPoolProperties(p);
con = datasource1.getConnection();
return con;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} finally {
return con;
}
finally {
System.out.println("before returning con: "+con);
if (con!=null) try {return con;}catch (Exception ignore) {}
return con;
}
}
}
Related
i am using JDBC to connect my MySQL database. I am trying to delete data from 2 tables (tasks and tasks_users(join table)). Look at my code:
#Override
public int deleteById(Long id) throws SQLException {
deleteByIdFromJoinTable(id);
int updated_rows;
sessionManager.beginSession();
try(Connection connection = sessionManager.getCurrentSession();
PreparedStatement statement = connection.prepareStatement(SQL_QUERIES.DELETE_TASK_BY_ID.QUERY)) {
statement.setLong(1, id);
updated_rows = statement.executeUpdate();
sessionManager.commitSession();
}catch (SQLException exception){
log.error(exception.getMessage(), exception);
sessionManager.rollbackSession();
throw exception;
}
return updated_rows;
}
public void deleteByIdFromJoinTable(Long id) throws SQLException {
sessionManager.beginSession();
try(Connection connection = sessionManager.getCurrentSession();
PreparedStatement statement = connection.prepareStatement(SQL_QUERIES.DELETE_TASK_FROM_TASKS_USERS.QUERY)) {
statement.setLong(1, id);
statement.executeUpdate();
sessionManager.commitSession();
}catch (SQLException exception){
log.error(exception.getMessage(), exception);
sessionManager.rollbackSession();
throw exception;
}
}
enum SQL_QUERIES {
DELETE_TASK_BY_ID("DELETE FROM tasks WHERE id=(?)"),
DELETE_TASK_FROM_TASKS_USERS("DELETE FROM tasks_users WHERE task_id=(?)");
final String QUERY;
SQL_QUERIES(String QUERY) {
this.QUERY = QUERY;
}
}
}
But when i call deleteById(), i get exception like:
13:58:03.079 [http-nio-8080-exec-9] DEBUG com.zaxxer.hikari.pool.ProxyConnection - restServiceDbPool - Executed rollback on connection com.mysql.cj.jdbc.ConnectionImpl#68421fee due to dirty commit state on close()
Connection to database works well, method, where i get all tasks returns them without problems.
What's problem is here, i will be very grateful for help?
I'm developping a RESTful API with Jersey and MySQL.
I'm actually using the JDBC driver to connect to the database and I create a new connection everytime I want to acess it. As it clearly is a memory leakage, I started to implement the ServletContextClassclass but I don't know how to call the method when I need to get the result of a SQL query.
Here is how I did it wrong:
DbConnection.java
public class DbConnection {
public Connection getConnection() throws Exception {
try {
String connectionURL = "jdbc:mysql://root:port/path";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
return connection;
}
catch (SQLException e) {
throw e;
}
}
}
DbData.java
public ArrayList<Product> getAllProducts(Connection connection) throws Exception {
ArrayList<Product> productList = new ArrayList<Product>();
try {
PreparedStatement ps = connection.prepareStatement("SELECT id, name FROM product");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Product product = new Product();
product.setId(rs.getInt("id"));
product.setName(rs.getString("name"));
productList.add(product);
}
return productList;
} catch (Exception e) {
throw e;
}
}
Resource.java
#GET
#Path("task/{taskId}")
#Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(#PathParam("taskId") int taskId) throws Exception {
try {
DbConnection database= new DbConnection();
Connection connection = database.getConnection();
Task task = new Task();
DbData dbData = new DbData();
task = dbData.getTask(connection, taskId);
return Response.status(200).entity(task).build();
} catch (Exception e) {
throw e;
}
}
Here is where I ended up trying to implement the new class:
ServletContextClass.java
public class ServletContextClass implements ServletContextListener {
public Connection getConnection() throws Exception {
try {
String connectionURL = "jdbc:mysql://root:port/path";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
return connection;
} catch (SQLException e) {
throw e;
}
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
DbConnection database = new DbConnection();
try {
Connection connection = database.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
//con.close ();
}
}
But problem is, I don't know what to do next. Any help? Thanks
You need to set the Connection variable as an attribute of the ServletContext. Also, I would recommend using connection as a static class variable so you can close it in the contextDestroyed method.
You can retrieve the connection attribute in any of your servlets later on for doing your DB operations.
public class ServletContextClass implements ServletContextListener {
public static Connection connection;
public Connection getConnection(){
try {
String connectionURL = "jdbc:mysql://root:port/path";
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
} catch (SQLException e) {
// Do something
}
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
getConnection();
arg0.getServletContext().setAttribute("connection", connection);
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
try{
if(connection != null){
connection.close();
}
}catch(SQLException se){
// Do something
}
}
}
Finally access your connection attribute inside your Servlet (Resource). Make sure you pass #Context ServletContext to your Response method so you can access your context attributes.
#GET
#Path("task/{taskId}")
#Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(#PathParam("taskId") int taskId, #Context ServletContext context) throws Exception {
try {
Connection connection = (Connection) context.getAttribute("connection");
Task task = new Task();
DbData dbData = new DbData();
task = dbData.getTask(connection, taskId);
return Response.status(200).entity(task).build();
} catch (Exception e) {
throw e;
}
}
Now that we have solved your current issue, we need to know what can go wrong with this approach.
Firstly, you are only creating one connection object which will be used everywhere. Imagine multiple users simultaneously accessing your API, the single connection will be shared among all of them which will slow down your response time.
Secondly, your connection to DB will die after sitting idle for a while (unless you configure MySql server not to kill idle connections which is not a good idea), and when you try to access it, you will get SQLExceptions thrown all over. This can be solved inside your servlet, you can check if your connection is dead, create it again, and then update the context attribute.
The best way to go about your Mysql Connection Pool will be to use a JNDI resource. You can create a pool of connections which will be managed by your servlet container. You can configure the pool to recreate connections if they go dead after sitting idle. If you are using Tomcat as your Servlet Container, you can check this short tutorial to get started with understanding the JNDI connection pool.
Do I need to obtain a context and DataSource in every method that reads/writes to the DB? (Sample below) Or does Play.db.DB's getConnection() method handle the pool transparently?
public void saveResponse() {
try {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx
.lookup("java:comp/env/jdbc/MySQLDB");
conn = ds.getConnection();
stmt = conn.createStatement();
stmt.execute("SOME SQL QUERY");
stmt.close();
stmt = null;
conn.close();
conn = null;
} catch (NamingException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
Play can manage that for you.
But why don't you use Play's JPA persistence?
http://www.playframework.com/documentation/1.2.5/jpa
That would be even more transparent than getting connections.
I am trying to connect to a MySQL database from a jsp page using jdbc in the backend.
I have the following code:
public static void insertIntoDatabase(String code,String name,String temp,String hum,String del) {
Connection con = null;
if (del.length() == 0) {
del="no data";
}
name = name.replaceAll("\\(.+?\\)", "");
name = name.replaceAll(" ", "_");
del = del.replaceAll(" ", "_");
System.out.println("del "+del);
String url = "jdbc:mysql://localhost:3306/test";
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url,"root","");
con.createStatement().executeUpdate("CREATE TABLE IF NOT EXISTS aiportdetails(code VARCHAR(50) PRIMARY KEY, " +
"name VARCHAR(250), temp VARCHAR(50), hum VARCHAR(50), del VARCHAR(50))");
ResultSet rs = con.prepareStatement("SELECT * FROM airportdetails;").executeQuery();
} catch (SQLException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
I am getting the following error at
ResultSet rs = con.prepareStatement("SELECT * FROM airportdetails;").executeQuery();
error:
Table 'test.airportdetails' doesn't exist
But from my phpmyadmin I can see that the table is created and exists:
What is the reason I am getting this error?
Thank you.
executeUpdate()
Executes the SQL statement in this PreparedStatement object, which must be an SQL INSERT, UPDATE or DELETE statement; or an SQL statement that returns nothing, such as a DDL statement.
Currently you are trying to use this for creating a table. That's the reason why you are getting that error.
Refer to the documentation Java 6 OR Java 1.4.2 for executeUpdate
EDIT:
You should create a table using Statement
Statement st = con.createStatement();
String table = "Create table .......";
st.executeUpdate(table);
you can put the initialize the connection and load driver at the constructor level, then in the method you can first createt check the table if it exists or create it then if it is successful, continue with the insert operation.like this:
public class MyBean{
String url = "jdbc:mysql://localhost:3306/test,"root","" ";
public MyBean(){
try{
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url);
}catch(Exception e){
}
}
public static void insertIntoDatabase(String code,String name,String temp,String hum,String del) {
Connection con = null;
if (del.length() == 0) {
del="no data";
}
name = name.replaceAll("\\(.+?\\)", "");
name = name.replaceAll(" ", "_");
del = del.replaceAll(" ", "_");
System.out.println("del "+del);
try {
con = DriverManager.getConnection(url);
Int result = con.createStatement().executeUpdate("CREATE TABLE IF NOT EXISTS aiportdetails(code VARCHAR(50) PRIMARY KEY, " +
"name VARCHAR(250), temp VARCHAR(50), hum VARCHAR(50), del VARCHAR(50))");
if(result>0){
try{
ResultSet rs = con.prepareStatement("SELECT * FROM airportdetails;").executeQuery();
}catch(Exception e){
}finally{
}
}//end if
} catch (SQLException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
I am trying to determine if I am actually using JDBC connection pooling. After doing some research, the implementation almost seems too easy. Easier than a regular connection in fact so i'd like to verify.
Here is my connection class:
public class DatabaseConnection {
Connection conn = null;
public Connection getConnection() {
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUrl("jdbc:mysql://localhost:3306/data");
bds.setUsername("USERNAME");
bds.setPassword("PASSWORD");
try{
System.out.println("Attempting Database Connection");
conn = bds.getConnection();
System.out.println("Connected Successfully");
}catch(SQLException e){
System.out.println("Caught SQL Exception: " + e);
}
return conn;
}
public void closeConnection() throws SQLException {
conn.close();
}
}
Is this true connection pooling? I am using the connection in another class as so:
//Check data against database.
DatabaseConnection dbConn = new DatabaseConnection();
Connection conn;
ResultSet rs;
PreparedStatement prepStmt;
//Query database and check username/pass against table.
try{
conn = dbConn.getConnection();
String sql = "SELECT * FROM users WHERE username=? AND password=?";
prepStmt = conn.prepareStatement(sql);
prepStmt.setString(1, user.getUsername());
prepStmt.setString(2, user.getPassword());
rs = prepStmt.executeQuery();
if(rs.next()){ //Found Match.
do{
out.println("UserName = " + rs.getObject("username") + " Password = " + rs.getObject("password"));
out.println("<br>");
} while(rs.next());
} else {
out.println("Sorry, you are not in my database."); //No Match.
}
dbConn.closeConnection(); //Close db connection.
}catch(SQLException e){
System.out.println("Caught SQL Exception: " + e);
}
Assuming that it's the BasicDataSource is from DBCP, then yes, you are using a connection pool. However, you're recreating another connection pool on every connection acquirement. You are not really pooling connections from the same pool. You need to create the connection pool only once on application's startup and get every connection from it. You should also not hold the connection as an instance variable. You should also close the connection, statement and resultset to ensure that the resources are properly closed, also in case of exceptions. Java 7's try-with-resources statement is helpful in this, it will auto-close the resources when the try block is finished.
Here's a minor rewrite:
public final class Database {
private static final BasicDataSource dataSource = new BasicDataSource();
static {
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/data");
dataSource.setUsername("USERNAME");
dataSource.setPassword("PASSWORD");
}
private Database() {
//
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
(this can if necessary be refactored as an abstract factory to improve pluggability)
and
private static final String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
public boolean exist(User user) throws SQLException {
boolean exist = false;
try (
Connection connection = Database.getConnection();
PreparedStatement statement = connection.prepareStatement(SQL_EXIST);
) {
statement.setString(1, user.getUsername());
statement.setString(2, user.getPassword());
try (ResultSet resultSet = preparedStatement.executeQuery()) {
exist = resultSet.next();
}
}
return exist;
}
which is to be used as follows:
try {
if (!userDAO.exist(username, password)) {
request.setAttribute("message", "Unknown login. Try again.");
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
} else {
request.getSession().setAttribute("user", username);
response.sendRedirect("userhome");
}
} catch (SQLException e) {
throw new ServletException("DB error", e);
}
In a real Java EE environement you should however delegate the creation of the DataSource to the container / application server and obtain it from JNDI. In case of Tomcat, see also for example this document: http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html
Doesn't seem like it's pooled. You should store the DataSource in DatabaseConnection instead of creating a new one with each getConnection() call. getConnection() should return datasource.getConnection().
Looks like a DBCP usage. If so, then yes. It's already pooled. And here is the default pool property value of the DBCP.
/**
* The default cap on the number of "sleeping" instances in the pool.
* #see #getMaxIdle
* #see #setMaxIdle
*/
public static final int DEFAULT_MAX_IDLE = 8;
/**
* The default minimum number of "sleeping" instances in the pool
* before before the evictor thread (if active) spawns new objects.
* #see #getMinIdle
* #see #setMinIdle
*/
public static final int DEFAULT_MIN_IDLE = 0;
/**
* The default cap on the total number of active instances from the pool.
* #see #getMaxActive
*/
public static final int DEFAULT_MAX_ACTIVE = 8;
As a follow up to BalusC's solution, below is an implementation that I can be used within an application that requires more than one connection, or in a common library that would not know the connection properties in advance...
import org.apache.commons.dbcp.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
public final class Database {
private static final ConcurrentHashMap<String, BasicDataSource> dataSources = new ConcurrentHashMap();
private Database() {
//
}
public static Connection getConnection(String connectionString, String username, String password) throws SQLException {
BasicDataSource dataSource;
if (dataSources.containsKey(connectionString)) {
dataSource = dataSources.get(connectionString);
} else {
dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(connectionString);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSources.put(connectionString, dataSource);
}
return dataSource.getConnection();
}
}