c3p0 CombopooledDataSource not committing SQL update - java

I am using a pooled datasource (msaccess database) to update local database (client side using h2 database) via an application i made.
The problem i have is when submitting a request say "INSERT INTO USERS (NAME, CODE) VALUES (Me ,hfd5255fd4);" the app runs perfectly , nothing is reported in the error log BUT nothing has changed in the database either.
The code i am using is as follows
private static Connection getDatabase() throws Exception {
cpds.setDriverClass("net.ucanaccess.jdbc.UcanaccessDriver");
// loads the jdbc driver
cpds.setJdbcUrl("jdbc:ucanaccess://"
+ (new File("Ressources/filter.mdb").getAbsolutePath()));
cpds.setUser("admin");
cpds.setPassword("ibnsina");
cpds.setAutoCommitOnClose(false);
return cpds.getConnection(); //tried removing this , but no effect
}
----doing some other stuff---
private static updating() throws exception{
conn = getDatabase();
File fileUpload = new File(logPath + "UploadLog.txt");
BufferedReader readerUpload = new BufferedReader(new FileReader(
fileUpload));
String Uploadingline = "";
StringBuffer secondaryline = new StringBuffer();
if (readerUpload.ready()) {
System.out.println("Uploadtxt ready");
Statement stUpload = conn.createStatement();
System.out.println("Stupload ready");
while ((Uploadingline = readerUpload.readLine()) != null) {
if (Uploadingline.endsWith(";")) {
secondaryline.append(Uploadingline);
/*stUpload.executeUpdate(secondaryline.toString()); tried this to execute each line separatly*/
stUpload.addBatch(secondaryline.toString());
System.out.println("Reading line :" + secondaryline);
secondaryline.setLength(0);
} else {
secondaryline.append(Uploadingline);
}
}
stUpload.executeBatch();
stUpload.clearBatch();
conn.commit(); //i even tried adding this to make it commit even tho autocommit is by default ON
stUpload.close();}

You should not create a new DataSource for each connection, you need to create just one DataSource and use that to get Connections. Remember to close() them as that will return the connection to the pool.
You should do something like:
// There should only ever be one of these.
private static final DataSource ds = makeDataSource();
private static DataSource makeDataSource() {
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("net.ucanaccess.jdbc.UcanaccessDriver");
// loads the jdbc driver
cpds.setJdbcUrl("jdbc:ucanaccess://"
+ (new File("Ressources/filter.mdb").getAbsolutePath()));
cpds.setUser("admin");
cpds.setPassword("ibnsina");
cpds.setAutoCommitOnClose(false);
return cpds;
}
private static Connection getConnection () {
return ds.getConnection();
}
private static void releaseConnection (Connection conn) {
conn.commit();
conn.close();
}
private static void updating() {
Connection conn = getConnection();
try {
//...
} finally {
releaseConnection(conn);
}
}

Related

User already has more than 'max_user_connections' active connections using HikariCP

I'm trying to use HikariCP for a Java EE app for school, but I don't understand why it doesn't work properly.. I'm making an API, and I'm using a MySQL Server with a Payara Server for my app.
I can call my API like 4 times before I get this error msg: http://prntscr.com/v7eopd The only way I found for solving is to restart Payara Server completely (even redeploy doesn't work)
I followed the HikariCP doc and configured my mysql.properties file as follow:
jdbcUrl = jdbc:mysql://mysql.iutrs.unistra.fr/devservweb?serverTimezone=UTC&useLegacyDatetimeCode=false
dataSource.user = user
dataSource.password = pwd
dataSource.cachePrepStmts=true
dataSource.prepStmtCacheSize=250
dataSource.prepStmtCacheSqlLimit=2048
dataSource.useServerPrepStmts=true
dataSource.useLocalSessionState=true
dataSource.rewriteBatchedStatements=true
dataSource.cacheResultSetMetadata=true
dataSource.cacheServerConfiguration=true
dataSource.elideSetAutoCommits=true
dataSource.maintainTimeStats=false
I did a DAO Pattern so, here is my DAOFactory for MySQL
public class MySQLDAOFactory extends DAOFactory {
private static final String PROPERTIES_FILE = "mysql.properties";
public Connection getConnection() throws SQLException, DAOConfigurationException {
Properties properties = new Properties();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream propertiesFile = classLoader.getResourceAsStream(PROPERTIES_FILE);
if(propertiesFile == null) {
throw new DAOConfigurationException("File " + PROPERTIES_FILE + " not found");
}
try {
properties.load(propertiesFile);
} catch (IOException e) {
throw new DAOConfigurationException("MySQL properties file could not be loaded " + PROPERTIES_FILE, e);
}
HikariConfig config = new HikariConfig(properties);
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
HikariDataSource ds = new HikariDataSource(config);
return ds.getConnection();
}
#Override
public FlightDAO getFlightDAO() {
return new MySQLFlightDAO(this);
}
#Override
public UserDAO getUserDao() {
return new MySQLUserDAO(this);
}
}
public abstract class DAOFactory {
public static DAOFactory getInstance(Persistence target) {
DAOFactory daoF = null;
switch (target) {
case MySQL:
daoF = new MySQLDAOFactory();
break;
}
return daoF;
}
public abstract FlightDAO getFlightDAO();
public abstract UserDAO getUserDao();
}
#Override
public User findByUsername(String username) throws DAOException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
User user = null;
try {
connection = dao.getConnection();
preparedStatement = initPreparedStatement(connection,
"SELECT user_id, username, password " +
"FROM user " +
"WHERE username = ?",
false,
username);
resultSet = preparedStatement.executeQuery();
if(resultSet.next()) {
user = map(resultSet);
}
} catch(SQLException e) {
throw new DAOException(e);
} finally {
closes(resultSet, preparedStatement, connection); // I'm using connection.close, statement.close and resultset.close inside this method
}
return user;
Before using HikariCP I used the default JDBC for getting connection and my code worked properly.
I can't find how to solve it because I though HikariCP manage pool automatically...
I'm in a hurry because I have to send it to my professor at the end of the week, so if someone can help me please, I do not find any help on google :( !
Thanks !

Multithreaded write on MySQL DB with JDBC and c3p0

I have written a DAO class which allows several threads invoked by ExecutorServices to write to MySQL DB.
EDIT: I am using c3p0 to create a JDBC ConnectionPool. So every new thread will get a new JDBC Connection by calling
DataBaseManager.getInstance().getConnection()
There seems to be random concurrency issue while executing, e.g:
java.sql.SQLException: No value specified for parameter 1
at com.eanurag.dao.DataBaseManager.writeData(DataBaseManager.java:102)
I am not able to understand all the issues with the code. Should I just synchronize entire writeData() ?
public class DataBaseManager {
private final static Logger logger = Logger.getLogger(DataBaseManager.class);
private static volatile DataBaseManager dbInstance = null;
private DataBaseManager() {
cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass("com.mysql.jdbc.Driver");
} catch (PropertyVetoException e) {
logger.error("Error in Initializing DB Driver class", e);
}
cpds.setJdbcUrl("jdbc:mysql://" + DB_HOST + "/" + DB_NAME);
cpds.setUser(DB_USER);
cpds.setPassword(DB_PASS);
cpds.setMinPoolSize(MINIMUM_POOL_SIZE);
cpds.setAcquireIncrement(INCREMENT_SIZE);
cpds.setMaxPoolSize(MAXIMUM_POOL_SIZE);
cpds.setMaxStatements(MAX_STATEMENTS);
}
public static DataBaseManager getInstance() {
if (dbInstance == null) {
synchronized (WorkerManager.class) {
if (dbInstance == null) {
dbInstance = new DataBaseManager();
}
}
}
return dbInstance;
}
private ComboPooledDataSource cpds;
private static final Integer MINIMUM_POOL_SIZE = 10;
private static final Integer MAXIMUM_POOL_SIZE = 1000;
private static final Integer INCREMENT_SIZE = 5;
private static final Integer MAX_STATEMENTS = 200;
private volatile Connection connection = null;
private volatile Statement statement = null;
private volatile PreparedStatement preparedStatement = null;
private static final String DB_HOST = "localhost";
private static final String DB_PORT = "3306";
private static final String DB_USER = "root";
private static final String DB_PASS = "";
private static final String DB_NAME = "crawly";
private static final String URL_TABLE = "url";
public Connection getConnection() throws SQLException {
logger.info("Creating connection to DB!");
return this.cpds.getConnection();
}
public Boolean writeData(URL url) {
StringBuffer writeDBStatement = new StringBuffer();
writeDBStatement.append("insert into");
writeDBStatement.append(" ");
writeDBStatement.append(DB_NAME);
writeDBStatement.append(".");
writeDBStatement.append(URL_TABLE);
writeDBStatement.append(" ");
writeDBStatement.append("values (?,?,default)");
Boolean dbWriteResult = false;
try {
connection = DataBaseManager.getInstance().getConnection();
preparedStatement = connection.prepareStatement(writeDBStatement.toString());
preparedStatement.setString(1, url.getURL());
preparedStatement.setString(2, String.valueOf(url.hashCode()));
dbWriteResult = (preparedStatement.executeUpdate() == 1) ? true : false;
if(dbWriteResult){
logger.info("Successfully written to DB!");
}
} catch (SQLException e) {
logger.error("Error in writing to DB", e);
} finally {
try {
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return dbWriteResult;
}
}
The connection and preparedStatement variables must be local, not instance members.
No synchronization required.
What is happening here?
public Connection getConnection() throws SQLException {
logger.info("Creating connection to DB!");
return this.cpds.getConnection();
}
Namely, what does cpds.getConnection() do? When you call:
connection = DataBaseManager.getInstance().getConnection();
Your connection object is a member of what's supposed to be a singleton class here but every call to writeData() overwrites it it with a new getConnection() call. Is the getConnection() call thread unsafe as well?
Also, why is the connection object declared as a class member and then overwritten each time writeData() is called? In a multi-threaded environment, the code as it exists allows for the connection object to be overwritten by another getConnection() call immediately before prepareStatement() is called, since access to writeData() is not locked. Same for preparedStatement. Move those into the writeData() method.

Connection pool abstract class

I am implementing an abstract class for connection pools. The goal is inherit this class to manage a connection pool for each database used in the program and encapsulate the common queries. I have serveral doubts:
Is efficient to get a connection from the pool and close it after do the query or is better implement it in another level to keep open the connection? (method selecSimple). I did a test with 100000 queries:
Took 86440 milliseconds getting and closing a connection from the pool for each query.
And 81107 milliseconds getting only one connection from the pool and using it to do all the queries, so I think there is not such a big difference.
I pass the ResultSet data to another container to release the connection as soon as posible, even if I have to go over the data twice, one to put the data into the new container and another later when it will be used. Do you think, it is a good practice or should be better to implement the queries in another level?
public abstract class ConnectionPool implements IConnectionPool {
/** Connection Pool dataSource */
private DataSource datasource;
#Override
public Connection getConnection() throws SQLException {
return datasource.getConnection();
}
#Override
public void closeConnectionPool() {
datasource.close();
}
#Override
public void setConnectionPool (String url, String driver, String user, String pass) throws SQLException {
// Using tomcat connection pool but it could be other
PoolProperties pool = new PoolProperties();
pool.setUrl(url);
// Set pool configuration
...
datasource = new DataSource();
datasource.setPoolProperties(pool);
}
// QUERIES
#Override
public List<Map<String, Object>> selectSimple (String query, String [] params) throws SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
Connection con = null;
List<Map<String, Object>> results = null;
// Set the preparedstatement
...
try {
con = getConnection();
ps = con.prepareStatement(selectString);
rs = ps.executeQuery(selectString);
results = resultSetToArrayList(rs);
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
throw new SQLException ();
} finally {
if (rs != null) rs.close();
if (ps != null) ps.close();
if (con != null) ps.close();
}
return results;
}
/** Transforms ResultSet into a List of Maps */
private List<Map<String, Object>> resultSetToArrayList(ResultSet rs) throws SQLException {
...
return list;
}
So, When the app finishes, will be enough closing the datasource to release the resources?(closeConnectionPool method).
I would greatly appreciate any help. Thanks in advance.

javax.sql.datasource getconnection returns null

Can someone please show me how to fix the code below so that it does not throw an error?
The following line of code is giving me a null pointer exception:
return dataSource.getConnection();
Note that dataSource is an instance of javax.sql.DataSource which is specified in web.xml, and which works fine when called by other code.
Here is the actual method in DataAccessObject.java where the null pointer is occurring:
protected static Connection getConnection(){
try {
return dataSource.getConnection(); //
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
The preceding method is being called by this line of code:
connection = getConnection();
Which is located in the following method in a class called CourseSummaryDAO as follows:
public List<CourseSummary> findAll(Long sid) {
LinkedList<CourseSummary> coursesummaries = new LinkedList<CourseSummary>();
ResultSet rs = null;
PreparedStatement statement = null;
Connection connection = null;
try {
connection = getConnection(); //
String sql = "select * from coursetotals where spid=?";
statement = connection.prepareStatement(sql);
statement.setLong(1, sid);
rs = statement.executeQuery();
//for every row, call read method to extract column
//values and place them in a coursesummary instance
while (rs.next()) {
CourseSummary coursesummary = read("findAll", rs);
coursesummaries.add(coursesummary);
}
return coursesummaries;
}catch (SQLException e) {
throw new RuntimeException(e);
}
finally {
close(rs, statement, connection);
}
}
To recreate this simply, I created the following TestCourseSummaries class:
public class TestCourseSummaries {
public static void main(String[] args) {
Long id = new Long(1002);
CourseSummaryDAO myCSDAO = new CourseSummaryDAO();
List<CourseSummary> coursesummaries = myCSDAO.findAll(id);
for(int i = 0;i<coursesummaries.size();i++){
System.out.println("type, numunits are: "+coursesummaries.get(i).getCourseType()+","+coursesummaries.get(i).getNumUnits());
}
}
}
EDIT:
To address JustDanyul's question, I am enclosing the code that calls in my application, and the underlying DataAccessObject code which is extended by the two DAO objects in the calling code:
Here is the code in my application which triggers the error. See there are two classes that each extended DataAccessObject. Perhaps they are conflicting with each other, causing the second one not to get the database connection?
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String idString = req.getParameter("id");
Long id = new Long(idString);
ThisObj thisobj = new ThisDAO().find(id);
req.setAttribute("thisobj", thisobj);
ThoseObjDAO myThoseDAO = new ThoseObjDAO();
List<ThoseObj> thoseobjects = myThoseObjDAO.findAll(id);
req.setAttribute("thoseobjects", thoseobjects);
jsp.forward(req, resp);
}
And here is the code for the DataAccessObject class which is extended by the two DAO classes in the calling code:
public class DataAccessObject {
private static DataSource dataSource;
private static Object idLock = new Object();
public static void setDataSource(DataSource dataSource) {
DataAccessObject.dataSource = dataSource;
}
protected static Connection getConnection() {
try {return dataSource.getConnection();}
catch (SQLException e) {throw new RuntimeException(e);}
}
protected static void close(Statement statement, Connection connection) {
close(null, statement, connection);
}
protected static void close(ResultSet rs, Statement statement, Connection connection) {
try {
if (rs != null) rs.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
} catch (SQLException e) {throw new RuntimeException(e);}
}
protected static Long getUniqueId() {
ResultSet rs = null;
PreparedStatement statement = null;
Connection connection = null;
try {
connection = getConnection();
synchronized (idLock) {
statement = connection.prepareStatement("select next_value from sequence");
rs = statement.executeQuery();
rs.first();
long id = rs.getLong(1);
statement.close();
statement = connection.prepareStatement("update sequence set next_value = ?");
statement.setLong(1, id + 1);
statement.executeUpdate();
statement.close();
return new Long(id);
}
}
catch (SQLException e) {throw new RuntimeException(e);}
finally{close(rs, statement, connection);}
}
}
The data source is created in web.xml, as follows:
<resource-ref>
<description>dataSource</description>
<res-ref-name>datasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
I suspect that the code where it "runs fine" in, is code actually running in an application server. The example you are posting, which just runs a static void main() method, wont get any resources which has been defined in web.xml.
I am guessing that you use JDNI to setup the initial datasource. And then using something like
#Resource(name="jdbc/mydb")
private DataSource dataSource;
to set up your connection. Right?
EDIT:
After seeing your code, it seems like your data source is newer initialised at all. Just putting a element into your web.xml will not do it alone. You will also need to actually configure the dataSource, you know, specify the driver, username, password, uri etc etc etc.
I'm guessing the find() method of the DAO that works, isn't actually using the dataSource. What you have shown so far, doesn't insigunate that your have a initialised dataSource at all.
Just to give you an idea, I liked a tutorial on how you would do this with Tomcat and JDNI. (Or even better, use spring-jdbc).
http://www.mkyong.com/tomcat/how-to-configure-mysql-datasource-in-tomcat-6/
Use dataSource as <javax.sql.DataSource> instance, rather than an instance of <javax.activation.DataSource>.
In short, you should replace the statement <import javax.activation.DataSource;> by this other <import javax.sql.DataSource;>.
Use dataSource as javax.sql.DataSource instance, rather than an instance of javax.activation.DataSource. In short, you should replace the statement:
import javax.activation.DataSource;
by this other:
import javax.sql.DataSource;

If I use a singleton class for a database connection, can one user close the connection for everybody?

I wrote a singleton class for obtaining a database connection.
Now my question is this: assume that there are 100 users accessing the application. If one user closes the connection, for the other 99 users will the connection be closed or not?
This is my sample program which uses a singleton class for getting a database connection:
public class GetConnection {
private GetConnection() { }
public Connection getConnection() {
Context ctx = new InitialContext();
DataSource ds = ctx.lookup("jndifordbconc");
Connection con = ds.getConnection();
return con;
}
public static GetConnection getInstancetoGetConnection () {
// which gives GetConnection class instance to call getConnection() on this .
}
}
Please guide me.
As long as you don't return the same Connection instance on getConnection() call, then there's nothing to worry about. Every caller will then get its own instance. As far now you're creating a brand new connection on every getConnection() call and thus not returning some static or instance variable. So it's safe.
However, this approach is clumsy. It doesn't need to be a singleton. A helper/utility class is also perfectly fine. Or if you want a bit more abstraction, a connection manager returned by an abstract factory. I'd only change it to obtain the datasource just once during class initialization instead of everytime in getConnection(). It's the same instance everytime anyway. Keep it cheap. Here's a basic kickoff example:
public class Database {
private static DataSource dataSource;
static {
try {
dataSource = new InitialContext().lookup("jndifordbconc");
}
catch (NamingException e) {
throw new ExceptionInInitializerError("'jndifordbconc' not found in JNDI", e);
}
}
public static Connection getConnection() {
return dataSource.getConnection();
}
}
which is to be used as follows according the normal JDBC idiom.
public List<Entity> list() throws SQLException {
List<Entity> entities = new ArrayList<Entity>();
try (
Connection connection = Database.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, foo, bar FROM entity");
ResultSet resultSet = statement.executeQuery();
) {
while (resultSet.next()) {
Entity entity = new Entity();
entity.setId(resultSet.getLong("id"));
entity.setFoo(resultSet.getString("foo"));
entity.setBar(resultSet.getString("bar"));
entities.add(entity);
}
}
return entities;
}
See also:
Is it safe to use a static java.sql.Connection instance in a multithreaded system?
Below code is a working and tested Singleton Pattern for Java.
public class Database {
private static Database dbIsntance;
private static Connection con ;
private static Statement stmt;
private Database() {
// private constructor //
}
public static Database getInstance(){
if(dbIsntance==null){
dbIsntance= new Database();
}
return dbIsntance;
}
public Connection getConnection(){
if(con==null){
try {
String host = "jdbc:derby://localhost:1527/yourdatabasename";
String username = "yourusername";
String password = "yourpassword";
con = DriverManager.getConnection( host, username, password );
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
}
}
return con;
}
While getting Connection in any Class simply use below line
Connection con = Database.getInstance().getConnection();
Hope it may help :)
package es.sm2.conexion;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConexionTest {
private static Connection conn = null;
static Connection getConnection() throws Exception {
if (conn == null) {
String url = "jdbc:mysql://localhost:3306/";
String dbName = "test";
String driver = "com.mysql.jdbc.Driver";
String userName = "userparatest";
String password = "userparatest";
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url + dbName, userName, password);
}
return conn;
}
}
To close Connection
public static void closeConnection(Connection conn) {
try {
conn.close();
} catch (SQLException e) {
}
}
To call to the connection:
package conexion.uno;
import java.sql.*;
import es.sm2.conexion.ConexionTest;
public class LLamadorConexion {
public void llamada() {
Connection conn = null;
PreparedStatement statement = null;
ResultSet resultado = null;
String query = "SELECT * FROM empleados";
try {
conn = ConexionTest.getConnection();
statement = conn.prepareStatement(query);
resultado = statement.executeQuery();
while (resultado.next()) {
System.out.println(resultado.getString(1) + "\t" + resultado.getString(2) + "\t" + resultado.getString(3) + "\t" );
}
}
catch (Exception e) {
System.err.println("El porque del cascar: " + e.getMessage());
}
finally {
ConexionTest.closeConnection(conn);
}
}
}
Great post, farhangdon! I, however, found it a little troublesome because once you close the connection, you have no other way to start a new one. A little trick will solve it though:
Replace if(con==null) with if(con==null || con.isClosed())
import java.sql.Connection;
import java.sql.DriverManager;
public class sql11 {
static Connection getConnection() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/ics", "root", "077");
return c;
}
}

Categories