H2 connection pool - java

I want to make a connection pool for my h2 database. But I think my pool opens new connection every time I call getConnection(). I guess there should be a fixed amount of reusable connections, but if I run this code :
Connection conn = DataSource.getInstance().getConnection();
Statement stmt = conn.createStatement();
ResultSet rs;
rs = stmt.executeQuery("SELECT * FROM NODE_USERS;");
while (rs.next()) {
System.out.println(rs.getString("login"));
}
try {
// wait a bit
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stmt.close();
rs.close();
conn.close();
DataSource:
public class DataSource {
private static volatile DataSource datasource;
private BasicDataSource ds;
private DataSource() throws IOException, SQLException, PropertyVetoException {
ds = new BasicDataSource();
ds.setUsername("sa");
ds.setPassword("sa");
ds.setUrl("jdbc:h2:tcp://localhost/~/test");
ds.setMinIdle(5);
ds.setMaxActive(10);
ds.setMaxIdle(20);
ds.setMaxOpenPreparedStatements(180);
}
public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException {
if (datasource == null) {
synchronized (DataSource.class) {
if (datasource == null) {
datasource = new DataSource();
}
}
datasource = new DataSource();
}
return datasource;
}
public Connection getConnection() throws SQLException {
return this.ds.getConnection();
}
}
and then execute select * from information_schema.sessions;, there will be two rows. What is wrong? Also I was trying H2 tutorial example, but I've got the same result.

You are using a connection pool, namely BasicDataSource. It will create a configured number of connections initially and then when getConnection() is called, it will either reused a free pooled connection or create a new one, up to a configured limit (or no limit if configured so). When the connection obtained is "closed" using Connection.close(), it is actually returned to the pool instead of being closed right away.
You basically have no control over how many open connctions there will be at a given time, apart of configuring the minimum and maximum allowed open connections. You observing two open connections therefore doesn't prove anything. If you want to see whether there is a limit on open connections, configure the BasicDataSource to use at most 2 connections using BasicDataSource.maxActive(), then try to obtain three connections at the same time. And for another test, with the same configuration, try obtaining two connections, returning them using Connection.close() and then obtaining another two connections.

Related

If using Hibernate with Database (and c3p0 dbpooling) is is still possible and safe to directly get connection bypassing Hibernate

Using Hibernate 4.3.11 with H2 1.4.199 and C3p0
If using Hibernate with Database is is still possible and safe to directly get connection from pool bypassing Hibernate?
Im trying to write an sql query, now I know I can use session.createSQLQuery() but this returns a Hibernate org.hibernate SQLQuery class rather than a java.sql.Connection and this is causing a problem for me trying to set the parameters, so I wanted to try using a Connection instead.
Try this.
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
sessionFactory.getSessionFactoryOptions().getServiceRegistry().getService(ConnectionProvider.class).getConnection();
I have not tested this and cannot do it at this time. I am only 50-50 on the ConnectionProvider, since I am not sure what the provider class for c3p0. May be org.hibernate.c3p0.internal.C3P0ConnectionProvider or you already know it.
EDIT 11-10-2019
The connections are returned from the implementations of org.hibernate.engine.jdbc.connections.spi.ConnectionProvider interface, as far as I can see.
org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl
org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl
Both these implementations are fetching a java.sql.Connection from Datasource or PooledConnections that are internally maintained at the time of service registry.
DatasourceConnectionProviderImpl has the following methods.
#Override
public Connection getConnection() throws SQLException {
if ( !available ) {
throw new HibernateException( "Provider is closed!" );
}
return useCredentials ? dataSource.getConnection( user, pass ) : dataSource.getConnection();
}
#Override
public void closeConnection(Connection connection) throws SQLException {
connection.close();
}
DriverManagerConnectionProviderImpl methods follow
#Override
public Connection getConnection() throws SQLException {
if ( !active ) {
throw new HibernateException( "Connection pool is no longer active" );
}
return pool.poll();
}
public Connection poll() throws SQLException {
Connection conn = availableConnections.poll();
if ( conn == null ) {
synchronized (allConnections) {
if(allConnections.size() < maxSize) {
addConnections( 1 );
return poll();
}
}
throw new HibernateException( "The internal connection pool has reached its maximum size and no connection is currently available!" );
}
conn.setAutoCommit( autoCommit );
return conn;
}
#Override
public void closeConnection(Connection conn) throws SQLException {
if (conn == null) {
return;
}
pool.add( conn );
}
And as you can see, they both have different ways of handling connections. I would not imagine major issues if you close the connection, since the first one returns new connection and the second one replenishes the pool if the connection is closed. However, if you are not going to close, know which implementation is getting invoked in your application and make sure you do not have a leak.
The other two implementations are for Hikari and UserSupplied mode.

Apache dbcp connection pooling not working properly

I am trying to connect to mysql database using apache dbcp2 connection pooling following its tutorial from here:
https://git-wip-us.apache.org/repos/asf?p=commons-dbcp.git;a=blob;f=doc/PoolingDataSourceExample.java;h=2a12c74898930b9623223db1597b8a8052a6f1df;hb=HEAD
My Database connection class that return the connection looks something like this:
public class DbConnection {
private static interface Singleton {
final DbConnection INSTANCE = new DbConnection();
}
private final PoolingDataSource<PoolableConnection> dataSource;
private DbConnection() {
// A ConnectionFactory that the pool will use to create Connections.
DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(url, user, pass); //url,user,pass for db connnection
//implement the pooling functionality.
PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null);
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxWaitMillis(500);
config.setMaxTotal(20);
config.setMaxIdle(5);
config.setMinIdle(5);
//PoolingDataSource expect an ObjectPool
ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config);
// Set the poolableConnectionFactory's pool property to the owning pool
poolableConnectionFactory.setPool(connectionPool);
this.dataSource = new PoolingDataSource<>(connectionPool);
}
public static Connection getCon() throws SQLException {
return Singleton.INSTANCE.dataSource.getConnection();
}
}
I am using apache jmeter to test the connection and return something from my mysql database. I created 100 users with Ramp-up periods(in seconds) being 2 second. I created a Http request and when I tried to see my response in view results tree I successfully get response for first 20 request. Later requests from (21 to 100) have blank response. I have gone through many of the issues involving:
java.sql.SQLException: Cannot get a connection, pool error Timeout
waiting for idle object
I access my code as:
try (PreparedStatement ps = DbConnection.getCon().prepareStatement("SELECT id FROM test WHERE id =?;")) {
ps.setString(1, id);
try (
ResultSet rs = ps.executeQuery()) {
return rs.next();
}
} catch (Exception ex) {
}
You aren't closing Connection object, you must declare such variable in try-with-resources block :
try (Connection conn = DbConnection.getCon();
PreparedStatement ps = conn.prepareStatement("SELECT id FROM test WHERE id =?;")) {
Also you need to close ResultSet, either call close method ResultSet in method or add it to try-with-resources block using a new method returning it

Websphere 7.0.0.17 error with Pool Connection

Im having a problem with an application, I'm using EclipseLink 2.4.1 with oracle 11g, I'm getting a J2CA0045E error, because the pooling does not set free any connections pool from the jndi,
Have you have this problem?, apparently the connection does not get released and it reach the limit I've configured.
Any ideas, this is my Connection pool
Connection timeout: 180
Maximum connections: 10
Minimum connections: 1
Reap time: 60
Unused timeout: 180
Aged timeout: 120
Purge policy: Entire Pool
EDIT
I have a web service in the same service, and the behavior is the same, using same jndi, the connection increase and does not release any connection
initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup("jdbc/abc");
conn = ds.getConnection();
Based on the code provided, it looks like you are storing the Connection reference at a class scope. You should avoid storing references to Connection objects that could span multiple requests.
Instead, store a reference to the DataSource.
To illustrate. This approach is preferred:
public class GoodService {
DataSource ds;
public GoodService() throws NamingException {
// Only the DataSource reference is stored, this is allowed
ds = new InitialContext().lookup("java:comp/env/jdbc/abc");
}
public void doSomething() throws Exception {
// Get the connection in a request.
Connection conn = ds.getConnection();
try {
// do something...
} finally {
// Always close the connection in the finally block
// so it gets returned to the pool no matter what
conn.close();
}
}
}
The following approach is considered bad practice, and is likely to cause the J2CA0045E error you are seeing:
public class BadService {
Connection conn; // BAD: don't store a Connection across requests!
public BadService() throws NamingException, SQLException {
DataSource ds = new InitialContext().lookup("java:comp/env/jdbc/abc");
// BAD: don't leave connections open indefinitely like this
conn = ds.getConnection();
}
public void doSomething() throws Exception {
// do something using conn...
}
}

Spring JdbcTemplate with DBCP BasicDataSource still closes connections

I'm using postgres jdbc driver to connect to Amazon RedShift. Here are also BasicDataSource from DBCP 2.0.1 and JdbcTemplate from Spring 4. I use DataSourceTransactionManager with Transactional annotations.
It looks like DataSource still keeps on creating new connections!
// that is how dataSource is created
BasicDataSource dataSource = new BasicDataSource() {
public Connection getConnection() throws SQLException {
Connection c = super.getConnection();
System.out.println("New connection: " + c);
return c;
}
};
dataSource.setUsername(env.getProperty(USERNAME));
dataSource.setPassword(env.getProperty(PASSWORD));
dataSource.setDriverClassName(env.getProperty(DRIVER_CLASS));
dataSource.setUrl(env.getProperty(CONNECTION_URL));
and I see in console for each operation another Connection object (they have different hashcodes). If I switch to SingleConnectionDataSource all works as expected, with a single connection object.
Before call to jdbcTemplate#execute I use TransactionSynchronizationManager.isActualTransactionActive to see that transactions are working (they are)...
What could I miss then? Why transactions are closed? Or what more can I do to investigate the problem. The url also have tcpKeepAlive=true parameter...
UPD thanks to Evgeniy, I've changed the code to see when connections are really created:
BasicDataSource dataSource = new BasicDataSource() {
protected ConnectionFactory createConnectionFactory() throws SQLException {
final ConnectionFactory cf = super.createConnectionFactory();
return new ConnectionFactory() {
public Connection createConnection() throws SQLException {
Connection c = cf.createConnection();
System.out.println("New connection from factory: " + c);
return c;
}
};
}
};
//dataSource.setMaxIdle(0);
Now I really see that only two connections were created (and if I add setMaxIdle(0) they are instead recreated before each query).
So my suspicion was wrong and pool works as expected. Thanks a lot!
Different hash codes do not prove they are different physical connections. Try to watch sessions on the database and you will see that close on connection from BasicDataSource does not close a physical connection.

Connection of c3p0 throws exception after MySQL timeout expired

I use c3p0 library of version 0.9.2.1 for creating a connection pool in a web application.
After MySQL timeout I get exception:
"HTTP Status 500 - The last packet successfully received from the
server was 627 301 milliseconds ago. The last packet sent successfully
to the server was 627 302 milliseconds ago. is longer than the server
configured value of 'wait_timeout'. You should consider either
expiring and/or testing connection validity before use in your
application, increasing the server configured values for client
timeouts, or using the Connector/J connection property
'autoReconnect=true' to avoid this problem."
I tried to append an autoReconnect parameter to JDBC url but there is no effect as well. So, in that way I use connection pool in my application:
For testing I have set wait_timeout of MySQL to 180 sec
set ##global.wait_timeout=180;
show global variables like "wait_timeout";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 180 |
+---------------+-------+
and further there are next pieces of code
c3p0.properties
# JDBC paramters are ommited
# Basic pool configuration
c3p0.initialPoolSize=5
c3p0.minPoolSize=5
c3p0.maxPoolSize=50
c3p0.acquireIncrement=5
# Managing connection age
c3p0.maxConnectionAge=100
c3p0.maxIdleTime=90
# Configuring connection testing
c3p0.idleConnectionTestPeriod=30
c3p0.testConnectionOnCheckin=true
c3p0.preferredTestQuery=SELECT 1
DBConnectionUtil.java
public class DBConnectionUtil {
// initialized through c3p0.properties
private static ComboPooledDataSource ds = new ComboPooledDataSource();
public static ComboPooledDataSource getConnectionPool() {
return ds;
}
public static void destroyConnectionPool() {
ds.close();
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
UserDAO.java
public class UserDAO {
private Connection connection;
public UserDAO() throws SQLException {
connection = DBConnectionUtil.getConnection();
}
public User find(Integer id) throws SQLException {
User user = null;
PreparedStatement ps = connection.prepareStatement("SELECT * FROM `USERS` WHERE ID = ?");
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
user = new User();
user.setId(rs.getInt("ID"));
user.setName(rs.getString("NAME"));
user.setUsername(rs.getString("USERNAME"));
user.setPassword(rs.getString("PASSWORD"));
user.setParentId(rs.getInt("PARENT_ID"));
}
rs.close();
ps.close();
return user;
}
}
DAOUtil.java
public class DAOUtil {
private static UserDAO userDAO;
public static UserDAO getUserDAO() {
return userDAO;
}
static {
try {
userDAO = new UserDAO();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
After expired MySQL wait_timeout, for instance, when I call DAOUtil.userDAO.find(id) it throws exception which was described above.
Could you help me to realize what I'm doing wrong, please?
Note: I can't change MySQL ini file.
Try to close connection in your Dao class and ask for new one from connection pool for every request to database.
Connection con;
try {
con=DBConnectionUtil.getConnection();
//some code here
} finally {
if(con!=null){
con.close();
}
And it's not safe to have Connection as a object field, better to use it as a local variable, because connection is not thread safe.

Categories