I am trying to get the jdbc connection using proxool connection pool in a Web application. Below code describes the same :
public static Connection getConnection(String key, boolean useConnectionPool, String poolName) {
Connection connection = null;
String alias = "DBCP" + poolName + "_" + key;
String driverClass = "com.mysql.jdbc.Driver";
checkAndLoadProps();
String driverUrl = "jdbc:mysql://" + props.getProperty(key + "_DBMS_URL") + "/" + props.getProperty(key + "_DEF_SCHEMA") + "?autoReconnect=true&useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=false&rewriteBatchedStatement=true";
String connectionPoolUrl = "proxool." + alias + ":" + driverClass + ":" + driverUrl;
try {
if (useConnectionPool) {
info.remove("user");
String user = props.getProperty(key + "_CLIENT");
info.setProperty("user", user);
info.remove("password");
String password = props.getProperty(key + "_CLIENT_PASS");
info.setProperty("password", password);
String host = props.getProperty(key + "_DBMS_URL");
synchronized (poolName) {
connection = DriverManager.getConnection(connectionPoolUrl, info);
}
}
if (connection != null) {
return connection;
} else {
System.out.println("DB Connection Not Established");
}
} catch (Exception ex) {
System.out.println("DB Connection Not Established::" + ex.getMessage());
ex.printStackTrace();
}
return null;
}
What happens is as soon as I start my server, more than 1 threads try to access this code parallely and it throws concurrent modification exception.
I understand it can be fixed by providing class level lock to the synchronized block. But it will severely affect the performance.
Any better solution to this?
For me your problem is more related to info
which is obviously an instance of Properties
that is shared. Knowing that Properties
extends Hashtable
and an Hashtable
will throw a ConcurrentModificationException
if you change its structure while iterating over it as stated into the javadoc:
if the
Hashtable
is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw aConcurrentModificationException
.
And here if you have several threads calling this method in parallel they could concurrently remove properties which modifies the structure of your Hashtable
and iterate over it within DriverManager.getConnection(connectionPoolUrl, info)
which would end up with a ConcurrentModificationException
.
What you should do is convert info
into a ConcurrentHashMap<Object, Object>
which is thread-safe and allows to be concurrently modified and iterated. Then you would provide as parameter to DriverManager.getConnection
, a Properties
instance created from info
as next:
private static Map<Object, Object> info = new ConcurrentHashMap<>();
public static Connection getConnection(String key, boolean useConnectionPool,
String poolName) {
...
Properties properties = new Properties();
properties.putAll(info);
connection = DriverManager.getConnection(connectionPoolUrl, properties);