My fear is that I have a fundamental issue with understanding connection pooling in Java.
I'm using IDBCDataSource as a connection pool.
At the entry point of my application I instantiate a BasicDataSource with for instance setMaxActive=50. The instance of that DataSource is than handed into various DAOs that are utilized by some business logic.
Each DAO calls getConnection(), but there is no single close() called. My assumption is that after a DAO is not used the garbage collector closes the connections.
My issue is that Im constantly running out of connections (i.e. code waiting for an available connection).
Now lets say I would add a close() call at the end of each database operation. What happens with thrown Exceptions. I would have to catch every Exception in the DAO, make sure to close the connection and then re-throw the occurred Exception!
Example - Current Approach:
public class MyDAO {
private Connection con;
public MyDAO (DataSource ds) {
con = ds.getConnection();
}
public MyReturnClass execSomeQuery() throws SQLException {
String sql = String.format("SELECT * FROM foo");
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
…
...
}
return result;
}
}
public class MyAppLogic() {
DataSource ds;
public MyAppLogic(DataSource ds) {
this.ds = ds;
}
public void doSomeStuff() {
MyDAO myDAO = MyDAO(ds);
myDAO.execSomeQuery();
}
}
You need to close the connections so that they return in the connection pool. GC will not call close on your connections!
You could create a wrapper or parent class that manages the connection, so that you don't have to replicate the logic in each method. Here's an example (note that I haven't actually compiled or tested this).
public interface DAOClass {
public void execSomeQuery() throws SQLException;
}
public class MyDAOWrapper {
private DAOClass dao;
private DataSource ds;
public MyDAOWrapper(DataSource ds, DAOClass dao) {
this.dao = dao;
this.ds = ds;
}
public void exec() throws SQLException {
Connection con = ds.getConnection();
try {
dao.execSomeQuery();
}
finally {
con.close();
}
}
}
// usage
public void doSomeStuff() throws SQLException {
MyDAOWrapper dao = new MyDAOWrapper(ds, new MyDAO());
dao.exec();
}
Regarding error handling, you don't need to rethrow an exception unless you catch it. Your finally clause should close the connection (if it exists) and when that exits, the exception will continue propagating up.
try {
do_something();
}
finally {
cleanup();
// throw is not necessary
}
Related
I found solution to rollback transaction when commit fails and It works perfectly.
But could you explain why Autorollback object close method is called first than connection close?
Autorollback class :
public class AutoRollback implements AutoCloseable {
private Connection conn;
private boolean committed;
public AutoRollback(Connection conn){
this.conn = conn;
}
public void commit() throws SQLException {
conn.commit();
committed = true;
}
#Override
public void close() throws SQLException {
if(!committed) {
conn.rollback();
}
}
}
example of service method that use Autorollback:
try(Connection connection = MySQLDAOFactory.getConnection();
AutoRollback autoRollback = new AutoRollback(connection)){
result = carDao.insertCar(connection,car);
autoRollback.commit();
} catch (SQLException | NamingException | MySQLEXContainer.MySQLDBExecutionException throwables) {
throw new ApplicationEXContainer.ApplicationCanNotChangeException(throwables.getMessage(),throwables);
}
Why does Autorollback's close method works?If connection is closed how can it call rollback method?So the only explanation is autorollback close method is called earlier thah connection close, but why?
Because that's how JLS says it has to work:
A try-with-resources statement is parameterized with variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block.
Source
I'm working on an app that retrieves from and enters information to a database, using Spring JDBC template. On the service tier, I would like to set up some logic to catch an exception if the database goes down. However, I have no idea how to do this. I'm able to set up the methods to catch if they fail, but I'd like set up specific logic for the server going down.
As an option - you can create a sceduler which will check database connectivity.
Database connectivity could be checked executing a simple query or via Connection interface:
boolean isValid(int timeout) throws SQLException
Returns true if the connection has not been closed and is still valid.
The driver shall submit a query on the connection or use some other
mechanism that positively verifies the connection is still valid when
this method is called. The query submitted by the driver to validate
the connection shall be executed in the context of the current
transaction.
An example of checking database connectivity via Spring scheduler:
#Service
public class ConnectionListener {
private Connection connection;
#Autowired
private JdbcTemplate jdbcTemplate;
#PostConstruct
public void init() {
connection = jdbcTemplate.getDatasource().getConnection();
}
#Scheduled(fixedRate = 60000) // check every 60 sec
public void checkConnection() {
try {
connection.isValid(10);
} catch (SQLException e) { // Or just handle it here
throw new ConnectionTimeoutException(e);
}
}
}
You need some additional cnfiguration to handle exceptions thrown from Spring Scheduler:
#EnableScheduling
#Configuration
class SchedulingConfiguration implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(...);
}
}
Sceduler also could be implemented with ExecutorService.
#Service
class ConnectionLisener {
private ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
private Connection connection;
#PostConstruct
public void init() {
connection = jdbcTemplate.getDatasource().getConnection();
checkConnection();
}
#PreDestroy
public void destroy() {
service.shutdown();
}
public void checkConnection() {
service.scheduleAtFixedRate(() -> {
try {
connection.isValid(10);
} catch (Exception e) {
// handle your exception
}
}, 60, 60, TimeUnit.SECONDS);
}
}
That's a general overview and just a couple of hints for doing further research.
Just one note that if a server is going down you need a disaster recovery, catching an exception will not help. That's a big infrastructure and architectural task, not the responsibility of single application.
I ask this question especially for Stateless Session Bean. I knew that I can easily inject the DataSource with the #Resource annotation. But I don't know what is the proper way to get the Connection. Is it in each method of the bean, or in the method annotated with #PostConstruct? And also for the closing of the Connection. Do I have to close it within the finally block in each method call, or in the method annotated with #PreDestroy?
Is it safe to create an instance variable for the Connection, for example:
#Stateless
public class MyBean {
#Resource private DataSource ds;
private Connection conn;
#PostConstruct
public void onCreate() {
conn = ds.getConnection(); // within try catch block
}
#PreDestroy
public void onDestroy() {
conn.close() // within try catch block
}
}
Or should I create them locally in each method like this:
#Stateless
public class MyBean {
#Resource private DataSource ds;
public void method1() {
Connection conn = null;
// get and close connection...
}
public void method2() {
Connection conn = null;
// get and close connection...
}
}
Some people in the Internet do this way, and some other do that way. What is the proper method to be implemented in an application with a high request traffic? When the bean instance is returned back to the EJB pool, does the Connection remains opened or does it returned to the database pool?
Note: The application is using native JDBC API. There are no JPA, JDO, etc.. The application server is Wildfly.
TL;DR
The second approach is the correct one. Just make sure to close the connection to return it to the Pool.
The Datasource is a pool of connections, every time you get a connection it borrows one from the datasource and when you close that connection it will be returned to the pool, so you will always want to release the connection as soon as possible.
In the first approach you will retain the connection for as long as the EJB lives in memory. Since the EJB is an Stateless bean it will be alive for long and reused by diferent consumenrs. Making you have at least 1 connection open per EJB that is alive thus this approach is not practical.
The second approach is the correct one. Just make sure to close the connection to return it to the Pool. With this approach the Bean will only retain the connection while in use. Just make sure to close the connection to return it to the Pool.
#Stateless
public class MyBean {
#Resource private DataSource ds;
public void method1() {
try(Connection conn = ds.getConnection()){
// Do anything you need with the connection
}
}
public void method2() {
Connection conn = ds.getConnection();
try {
// Do anything you need with the connection
} finally {
connection.close();
}
}
}
When you inject a datasource in your application and get a connection by invoking getConnection() on it, are you supposed to close the connection?
Even though the datasource itself is container managed, the API indeed requires the programmer to close connections. This is different from a couple of other container managed resources (like the entity manager), where the container takes care of closing. Note that closing here in the majority of cases doesn't actually closes the connection here, but returns the connection to a connection pool.
As a rule of thumb, if you use a factory-ish resources to obtain one or more other resources from that can be closed, you have to close them. Otherwise the container does this.
Since Connection implements AutoCloseable, you can use a try-with-resources block for this:
#Stateless
public class MyBean {
#Resource(lookup = "java:/app/datasource")
private DataSource dataSource;
public void doStuff() {
try (Connection connection = dataSource.getConnection()) {
// Work with connection here
} catch (SQLException e) {
throw new SomeRuntimeException(e);
}
}
}
Of course, otherwise you'll exhaust your connection pool. It's best to do this in finally block:
#Resource(mappedName="jndi/yourDatasource")
DataSource ds;
..
Connection conn = null;
try {
conn = ds.getConnection();
//PERFORM QUERY, ETC..
}
catch(SQLException ex) {
//EXCEPTION HANDLING
}
finally {
try {
if(conn != null)
conn.close();
}
catch(SQLException ex) {..}
}
My requirement is quite similar to this one except that my long running IO operation is a database select.
One rather rather creative solution suggested in that thread, involved closing the IO stream in a separate thread. However, I don't really have a reference to the input stream or socket.
I can't even close the connection being used as I use spring-jdbc, which does not provide me access to the underlying connection being used. I believe JdbcTemplate.getDataSource().getConnection() will potentially return another connection from the data source.
Appreciate any help/suggestions i can get.
Use JdbcTemplate.execute(PreparedStatementCreator, PreparedStatementCallback)
In the PreparedStatementCreator, you get access to the Statement, which you can give to another thread. This other thread creates a timer and calls .cancel on the Statement if necessary.
As Istvan Mentioned, PreparedStatementCreator is the way to go.
Pasting my implementation in case its helpful ..
private final long timeout = 1000; //timeout in seconds
final SqlRowSet rowSet = jdbcTemplate.getJdbcOperations().query(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
if (timeout>0){
Timer timer = new Timer();
timer.schedule(new ConnectionInterrupter(con), timeout*1000);
}
return con.prepareStatement(queryString);
}
}, new ResultSetExtractor<SqlRowSet>() {
#Override
public SqlRowSet extractData(ResultSet rs) throws SQLException, DataAccessException {
CachedRowSet rowSet = newCachedRowSet();
rowSet.populate(rs);
return new ResultSetWrappingSqlRowSet(rowSet);
}
protected CachedRowSet newCachedRowSet() throws SQLException {
return new CachedRowSetImpl();
}
});
private class ConnectionInterrupter extends TimerTask {
private final Connection connection;
public ConnectionInterrupter(Connection connection) {
this.connection = connection;
}
#Override
public void run() {
try {
logger.warn("Connection timeout has occurred. Manually closing the connection ...");
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}