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);
}
}
}
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.
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/
Basically, I'm doing some SQL Querying on a remote database, and I've been told to always run queries in a seperate thread to not bother the loop of the main application (Considering it's a real time game). I'm just getting around to adding SQL support and not running the queries on a seperate thread causes massive lag; Here's what I'm attempting to do:
public boolean login(final String username, final String password) {
final AtomicBoolean value = new AtomicBoolean(false);
Thread thread = new Thread(new Runnable() {
public void run() {
Connection connection = null;
Statement statement = null;
ResultSet results = null;
try {
connection = getConnection("root", "", "localhost");
statement = connection.createStatement();
results = statement.executeQuery("SELECT * from `db`.`accounts` WHERE `username`='"+username+"'");
while(results.next()) {
String salt = results.getString("salt");
String dbPass = results.getString("password");
String hashPass = toMD5(toMD5(salt) + toMD5(password));
if(hashPass.equals(dbPass)) {
value.set(true);
}
}
} catch(SQLException e) {
e.printStackTrace();
}
}
});
thread.start();
return value.get();
}
However, the problem is that the value of the atomic boolean is never set before the application is returned. I'm trying to find the best way to do this without blocking the thread that I'm calling on.
Note: Well aware I should be using prepared statements here, trying to figure this out first.
I'm trying to find the best way to do this without blocking the thread that I'm calling on.
That is impossible. If that thread needs the result, it will have to block until that result is available.
One option is to use a CompletableFuture<Boolean>.
CompletableFuture<Boolean> future = new CompletableFuture<>();
Thread thread = new Thread(new Runnable() {
public void run() {
...
// when ready, successful (maybe false otherwise)
future.complete(true)
...
}
});
You can then either call future.get() which blocks the current thread or you can register a listener which will be invoked when the result is set (in that other thread, or in the current thread if the result is already ready).
Instead of managing your own thread, use a thread pool.
I'm trying to find the best way to do this without blocking the thread that I'm calling on.
What you need is a listener, that can listen for your thread to finish and then execute your code.
Let's assume that you want to return a ResultSet from your thread. First, you create your own EventObject.
package com.ggl.event.listener;
import java.sql.ResultSet;
import java.util.EventObject;
public class ResultSetEventObject extends EventObject {
private static final long serialVersionUID = 6904165475135245131L;
private ResultSet resultSet;
public ResultSetEventObject(Object source) {
super(source);
}
public ResultSet getResultSet() {
return resultSet;
}
public void setResultSet(ResultSet resultSet) {
this.resultSet = resultSet;
}
}
There’s nothing special about this class, other than it extends EventObject. Your constructor is defined by EventObject, but you can create any methods you want.
Second, you define an EventListener interface.
package com.ggl.event.listener;
public interface EventListener {
public void handleEvent(ResultSetEventObject eo);
}
You would use the EventObject you created. You can use any method name or names that you want. This is the interface for the code that will be written as a response to the listener.
Third, you write a ListenerHandler.
package com.ggl.event.listener;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class ResultSetListenerHandler {
protected List<EventListener> listeners;
public ResultSetListenerHandler() {
listeners = new ArrayList<EventListener>();
}
// Add method(s) to generate a ResultSet and perform the
// fireEvent method.
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void removeListener(EventListener listener) {
for (int i = listeners.size() - 1; i >= 0; i--) {
EventListener instance = listeners.get(i);
if (instance.equals(listener)) {
listeners.remove(i);
}
}
}
public void fireEvent(final ResultSetEventObject eo,
final ResultSet resultSet) {
for (int i = 0; i < listeners.size(); i++) {
final EventListener instance = listeners.get(i);
Runnable runnable = new Runnable() {
public void run() {
eo.setResultSet(resultSet);
instance.handleEvent(eo);
}
};
new Thread(runnable).start();
}
}
}
And that's how you write an event listener. In your code, you would write something like this:
ResultSetListenerHandler handler = new ResultSetListenerHandler();
handler.addListener(new EventListener() {
#Override
public void handleEvent(ResultSetEventObject eo) {
// Code to process the eo ResultSet goes here
}
});
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
}