How to catch a broken database connection - java

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.

Related

Proper way to handle JDBC connection in EJB 3 (SLSB)

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();
}
}
}

The best way to implement producer-consumer in web app

Here is my scenario:
Each minute one thread checks database looking for some items.
When items are found, they are passed to the another thread(consumer).
I use spring in my application, but it doesn't meant that I must use spring's classes, right?
So, now I'm totally lost in the woods of ScheduledExecutorService (java), ExecutorService (java), TaskExecutor (spring), TaskScheduler (spring), #Scheduled (spring).
Help me please to understand what is the right way to implement my scenario.
If I understand your question, you are using a Shared Database Pattern which, for for many reason is somewhat discouraged and used as a last resource.
If you want multiple application to communicate, and be decoupled, you should use Messaging ( eg: Spring Cloud Stream ).
Anyway, if you need to have a Shared Database, you may want what Listen / Notify provide.
From https://jdbc.postgresql.org/documentation/81/listennotify.html:
import java.sql.*;
public class NotificationTest {
public static void main(String args[]) throws Exception {
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/test";
// Create two distinct connections, one for the notifier
// and another for the listener to show the communication
// works across connections although this example would
// work fine with just one connection.
Connection lConn = DriverManager.getConnection(url,"test","");
Connection nConn = DriverManager.getConnection(url,"test","");
// Create two threads, one to issue notifications and
// the other to receive them.
Listener listener = new Listener(lConn);
Notifier notifier = new Notifier(nConn);
listener.start();
notifier.start();
}
}
Listener
class Listener extends Thread {
private Connection conn;
private org.postgresql.PGConnection pgconn;
Listener(Connection conn) throws SQLException {
this.conn = conn;
this.pgconn = (org.postgresql.PGConnection)conn;
Statement stmt = conn.createStatement();
stmt.execute("LISTEN mymessage");
stmt.close();
}
public void run() {
while (true) {
try {
// issue a dummy query to contact the backend
// and receive any pending notifications.
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1");
rs.close();
stmt.close();
org.postgresql.PGNotification notifications[] = pgconn.getNotifications();
if (notifications != null) {
for (int i=0; i<notifications.length; i++) {
System.out.println("Got notification: " + notifications[i].getName());
}
}
// wait a while before checking again for new
// notifications
Thread.sleep(500);
} catch (SQLException sqle) {
sqle.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
Notifier
class Notifier extends Thread {
private Connection conn;
public Notifier(Connection conn) {
this.conn = conn;
}
public void run() {
while (true) {
try {
Statement stmt = conn.createStatement();
stmt.execute("NOTIFY mymessage");
stmt.close();
Thread.sleep(2000);
} catch (SQLException sqle) {
sqle.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
Instead of using ScheduledExecutorService you can user quartz scheduler that is used to schdule some jobs in specific intervals, in your case every minute. It can be easily integrated with spring.
Cron expressions are used to specify the time when to schedule.
You can write your logic that checks database looking for some items in a class that extends QuartzJobBean class.
See:
https://examples.javacodegeeks.com/enterprise-java/quartz/spring-quartz-scheduler-example/

Async service with session

I have a method that is going to call a stored function. I want it to async'ly do its work. This is what I have, but it seems like the .doWork() is never started because when I call getDao.deleteAll(), the stored function does not run.
#Transactional
public void delete()
{
final Session session = (Session) entityManager.getDelegate();
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable()
{
#Override
public void run()
{
LOGGER.warn("starting");
session.doWork(new Work()
{
#Override
public void execute(Connection connection) throws SQLException
{
try
{
CallableStatement purgeArchived = connection.prepareCall("{call deleteAll()}");
purgeArchived.execute();
}
catch (SQLException exception)
{
LOGGER.warn("Failed to purge archive points. Reason: " + exception);
}
}
});
LOGGER.warn("stopping");
}
});
executorService.shutdown();
}
I see the logger has logged "starting", but it never got to "stopping" why is this happening?
Be aware that #Transaction is moot when you have a separate thread as Transactions are typically thread bound.
You will need to get a new entityManager from the factory inside the run().
Also go for #Async which is much cleaner.
Again be aware of transactionality with #Async
#Async and #Transactional: not working
As a general rule of thumb if you want to make some work async - treat that as a single unit of work and a separate transaction.

Java Connection Pooling - garbage collection or call close()?

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
}

Interrupt a thread performing a long running database select

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);
}
}
}

Categories

Resources