I have a java process which is multi threaded using ExecutorService (15 threads). Each thread calls store procedure to insert data to table, my connection to be pooled across 15 threads so that I could see multiple commits on the table at the same time, but i only see one connection established for one active thread even through 15 threads are ready and waiting.
Driver: oracle.jdbc.driver.OracleDriver
Following are the connection details I have in my properties file
url, username, password
Class.forName(DB_DRIVER);
DataSource oracleDataSource = new DriverManagerDataSource(DB_CONNECTION, DB_USER,DB_PASSWORD);
ObjectPool objectPool = new GenericObjectPool();
DataSourceConnectionFactory datasourceConnectionFactory = new DataSourceConnectionFactory(oracleDataSource);
PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(datasourceConnectionFactory, objectPool, null, null, false, true);
objectPool.setFactory(poolableConnectionFactory);
PoolingDataSource datasource = new PoolingDataSource(objectPool)
Oracle has Universal Connection Pool (ucp.jar) which is easy to use and is from oracle. All you need is to include ucp.jar in the classpath along with ojdbc6.jar or ojdbc7.jar.
Refer to the UCP Reference Guide: http://docs.oracle.com/database/121/JJUCP/toc.htm
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setMinPoolSize(10);
pds.setMaxPoolSize(50);
Connection conn=pds.getConnection();
You need a connection pool.
Either the object that manages the executor pool will check out a connection, give it to the ExecutorService, and close it when the task completes OR the ExecutorService will manage it. Make sure that you pay careful attention to connection management and SQL resource cleanup or you'll quickly have problems under high request volume.
Usually it's Java EE app servers that manage connection pools for you, but it sounds like you aren't using one. If that's true, perhaps Apache Database Connection Pool will suit your purpose.
Related
I use Hikary connection pool with following settings:
HikariDataSource dataSource = new HikariDataSource();
dataSource.setMinimumIdle(0);
dataSource.setMaximumPoolSize(Integer.MAX_VALUE);
dataSource.setJdbcUrl(jdbcConnectionString);
dataSource.setConnectionTestQuery("select 1");
dataSource.setIdleTimeout(TimeUnit.SECONDS.toMillis(60));
dataSource.getConnection();
After getConnection() hikari try to get 2 connections to instance, but put in connection pool just one connection. How can I fix it? The hikari version is 3.4.0
I found the answer. Hikari creates first connection in checkFailFast method. I update this comment when find how to disable this method. The checkFailFast doesn't work if initializationFailTimeout<0. It helps me
After getConnection() hikari try to get 2 connections to instance, but put in connection pool just one connection. How can I fix it?
There is nothing to fix in this behavior. It simple means, that two conenctions were opened and one of them was closed.
The reason why the second connection was closed is that you set setMinimumIdle(0), i.e. no idle connection is maintainend in the pool and all idle connection are closed.
If you want to see both connection in the pool, simple set setMinimumIdle(1). After calling DataSource.getConnection() there will be two connection in the pool - one yours and one idle.
If you don't want to open the second connection at all, set
config.setMinimumIdle( 1 );
config.setMaximumPoolSize( 1 );
But think twice, why do you use a connection pool with only one connection.
You may anyway increase both parameters later, while the pool is running.
HikariConfigMXBean bn = DataSource.ds.getHikariConfigMXBean()
bn.setMaximumPoolSize(10)
bn.setMinimumIdle(10)
This will (not instantly) open 9 additional connections to the database.
Note that while setting the MaximumPoolSize == MinimumIdle the number of connection in the pool remains stable, no connections are opened or closed, which is probably the thing you want to observe.
Tested with Hicari 3.4.0 and Oracle 12.2
My system encounter some connection leak in connection pool. I would like to list down some statistic of the connection pool regularly, how can I do that? For example, Current Capacity, Active Connections High Count, Connections Total Count, Leaked Connection Count and etc.
I am using javax.sql.DataSource to retrieve the connection from connection pool. But I couldn't find any interface that can retrieve those connection pool information. Any ideas?
I am using Oracle DB and Java EE as my server side script.
The javax.sql.DataSource is an interface and it just abstracts a data source. It does not involve providing pooled connections to it.
A connection pool is responsible for providing pooled, reusable connections to a database (data source).
First you need to find out which connection pool you're using. Connection pool implementations usually provide a way to query things like the number of active connections.
For example the Apache DBCP has a BasicDataSource class which is a connection pool, and it has a methods for this:
BasicDataSource.getMaxTotal();
BasicDataSource.getNumActive();
BasicDataSource.getNumIdle();
BasicDataSource.getMinIdle();
BasicDataSource.getMaxIdle();
Since you mentioned you're using Oracle DB, most likely your connection pool is OracleOCIConnectionPool (part of Oracle JDBC driver) which provides:
OracleOCIConnectionPool.getMaxLimit();
OracleOCIConnectionPool.getPoolSize();
OracleOCIConnectionPool.getActiveSize();
OracleOCIConnectionPool.getMinLimit();
A console application executing under:
1). Multiple threads
2). Connection Pooling (as the database connections range could be 5 to 30) of type Microsoft Access using DBCP.
While executing this application at my end (not tested the database limit) it works fine. And whenever I try to introduce the same application on one of other machines it generates an error.
I'm wondering why this is happening as there is only the difference of machines here. So, it works perfectly at my end.
I don't know much about connection pooling but it seems whatever I have understood I have implemented as:
public class TestDatabases implements Runnable{
public static Map<String, Connection> correctDatabases;
#Override
public void run() {
// validating the databases using DBCP
datasource.getConnection(); // Obtaining the java.sql.Connection from DataSource
// if validated successfully °º¤ø,¸¸,ø¤º°`°º¤ø,¸,ø¤°º¤ø,¸¸,ø¤º°`°º¤ø,¸ putting them in correctDatabases
}
}
The above case is implemented using ExecutorService = Number of databases.
Finally, I'm trying to put them in a static Collection of Type
Map<String, Connection> and making use of it throughout the application. In other words: I'm trying to collect the connectionString along with the Connection in a Map.
In other parts of my application I'm simply dealing with multiple threads coming along with the Connection URL. So, to perform any database operations I'm calling the
Connection con = TestDatabases.correctDatases.get(connectUrl);
For that machine, this application works fine for around ~5 databases. And the error is always getting generated when I'm trying to fire the query using above Connection (con) as stmt.executeQuery(query);
As, I'm not able to reproduce this issue at my end, it seems something is going-on wrong with the Connection Pooling or I have not configured my application to deal with Connection Pooling correctly.
Just for your information, I'm correctly performing Connection close in finally block where my application terminates and this Application is using Quartz Scheduler as well. For Connection Pooling, a call to the following from TestDatabases class is done for setUp as:
public synchronized DataSource setUp() throws Exception {
Class.forName(RestConnectionValidator.prop.getProperty("driverClass")).newInstance();
log.debug("Class Loaded.");
connectionPool = new GenericObjectPool();
log.debug("Connection pool made.");
connectionPool.setMaxActive(100);
ConnectionFactory cf = new DriverManagerConnectionFactory(
RestConnectionValidator.prop.getProperty("connectionUrl")+new String(get().toString().trim()),
"","");
PoolableConnectionFactory pcf =
new PoolableConnectionFactory(cf, connectionPool,
null, null, false, true);
return new PoolingDataSource(connectionPool);
}
Following is the error I'm getting (at the other machine)
java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver] System resource exceeded.
Following is the Database Path:
jdbc:odbc:DRIVER= {Microsoft Access Driver (*.mdb, *.accdb)};DBQ=D:\\DataSources\\PR01.mdb
Each of those database seems to be not much heavy (its ~ 5 to 15 MB of total size).
So, I'm left with the following solutions:
1). Correction of Connection Pooling or migrate to the newer one's like c3p0 or DBPool or BoneCP.
2). Introducing batch concept - in which I will schedule my application for each group of 4 databases. It could be very expensive to deal with as any time the other schedule may also collapse.
I’m pretty sure that this is Java related error but I can’t fathom out why.
Just done the migration to BoneCP which solved my problem. I guess due to multi-threaded environment the dpcp was not providing the connection from pool rather it was trying to hit the database again and again. Maybe I could have solved the dpcp issue but migrating to BoneCP also provides advantage of performance.
Referring to Tomcat JBDC connection pool, I see in the standalone java example given there, one gets the connection using datasource.getConnection()which is cool. But in the finally block, it says con.close().
Question: When I implement this, it seems obvious that the con I get from datasource will be closed every time in the finally. When this is closed, will the connection pooling mechanism acquire a new connection and adds it to the pool?
I presume there should be a method call like releaseConnection() that will let the pool take its own decision whether to close it or let it be open for some other use.
I've also tried doing this ConnectionPool aPool = datasource.createPool();
But I see there is nothing like release connection on this aPool.
I think I'm missing something here?
Appreciate your help.
Code snippet from Tomcat JBDC connection pool:
DataSource datasource = new DataSource();
datasource.setPoolProperties(p);
Connection con = null;
try {
con = datasource.getConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select * from user");
int cnt = 1;
while (rs.next()) {
System.out.println((cnt++)+". Host:" +rs.getString("Host")+
" User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
}
rs.close();
st.close();
} finally {
if (con!=null) try {con.close();}catch (Exception ignore) {}
}
Since you call the close() on a method obtained by the pool it is up to the pool what to do inside this method call. It does not neccessarily have to close the pooled database connection - it may do some cleanup and then add the connetion back to the pool.
This is already answered in Closing JDBC Connections in Pool
OK, my bad, that I did not see the implementation of DataSource.
It extends DataSourceProxy that internally creates a pool before returning a Connectionbased on the PoolProperties
I understand, its upto this DataSource to handle the connections, even though I close the con in finally, DataSource may take necessary action.
Do add a comment/reply if anybody thinks otherwise.
That example only shows how to create and use a data source. For connection pool on Tomcat you may configure JNDI.
// Sample
public static Connection getConnectionFromPool() {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup("jdbc/TestDB");
return ds.getConnection();
...
Quote from How connection pooling works in Java and JDBC:
A connection pool operates by performing the work of creating
connections ahead of time, In the case of a JDBC connection pool, a
pool of Connection objects is created at the time the application
server (or some other server) starts. These objects are then managed
by a pool manager that disperses connections as they are requested by
clients and returns them to the pool when it determines the client is
finished with the Connection object. A great deal of housekeeping is
involved in managing these connections.
When the connection pool server starts, it creates a predetermined
number of Connection objects. A client application would then perform
a JNDI lookup to retrieve a reference to a DataSource object that
implements the ConnectionPoolDataSource interface. The client
application would not need make any special provisions to use the
pooled data source; the code would be no different from code written
for a nonpooled DataSource.
I have created a mysqlDatasource connection using the following code:
MysqlDataSource d = new MysqlDataSource();
d.setUser("user");
d.setPassword("pass");
d.setServerName("hostname.com");
d.setDatabaseName("db");
Connection c = d.getConnection();
If Im running my application and the connections are disconnected because mysql restarted or for some other reason, the remaining operations will fail even if the mysql server instance is running.
In that case I want to recreate a connection? Is this possible? How do I go about doing this?
In most cases when you're creating multiple connections and juggling them, it's better to use a connection pool, where the Connection objects are just that, objects, and are multiplexed to actual socket connections handled by an underlying implementation. This means that connections are created automatically when you need them and you don't need to worry about reclaiming resources and creating an appropriate number of connections.
Two prominent examples are BoneCP and C3P0.
The other option, in addition to Mr Mao's, is to define the url explicitly using setURL to allow for automatic reconnection, using the autoReconnect parameter, do note, though, that this approach is not recommended. The answer is provided here only for completeness.
Just take an help of DBCP CONNECTION and create your Connection pool like below code. You can see there is validation query which pings database at regular interval and refreshes the pool. There are other property like validateConnection you can set this property to true.
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setUrl("jdbc:mysql://<host>:<port>/<database>");
dataSource.setMaxActive(50);
dataSource.setMaxIdle(5);
dataSource.setInitialSize(5);
dataSource.setValidationQuery("SELECT 1");
Try this.
String driver = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
Class.forName(driver);
String url = "jdbc:microsoft:sqlserver://host:1433/database";
Connection conn = DriverManager.getConnection(url, "username", "password");