Reputation: 21486
We have a class we've written which opens up a connection to a server. When you're done with it, you need to either tell it to commit
if everything was successful, or tell it to rollback
if something went wrong. So right now we have a lot of spots in our code that look like this:
OurConnectionClass conn = null;
try {
conn = OurConnectionClass(parameters);
// Do some stuff here...
conn.commit();
} catch (Throwable t) {
if (conn != null) {
conn.rollback();
}
throw t;
}
If you forget to commit or rollback, there's no immediate issues, but eventually you exhaust a connection pool and then have to figure out where you made a mistake.
I'd like to find a way so OurConnectionClass
implements AutoClosable
, so I could do somsething like this instead:
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
}
I feel like there has to be a way to do this, but I'm not seeing it. AutoCloseable
only calls a close
method, with no arguments passed to it. As far as I can see, there's no way to know whether close is being called because the end of the try block was successfully reached or because an exception was thrown.
Upvotes: 4
Views: 1490
Reputation: 425043
Do both!
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
conn.commit();
} catch (Throwable t) {
conn.rollback();
throw t;
}
The closeable is still auto-closed (in the implicit finally
block) if stuff explodes.
BTW, it would be better to throw a domain exception:
throw new MyStuffExploded(t);
because re-throwing the connection exception lets implementation details leak out via the method contract, which is a form of coupling, which is bad.
Upvotes: -1
Reputation: 5545
I think the semantic you want is that the transaction is rolled back in close, unless the code which uses OurConnectionClass explicit calls OurConnectionClass.commit().
Then you don't have any problem, because your close method, then just need to test if there is an open transaction. And if there is roll it back, and log an error.
Upvotes: 1
Reputation: 19926
When executing this snippet.
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
conn.commit();
}
OurConnectionClass.close()
will always be called after an instance is created. So you can just add some logic to check if a commit was made. E.g. with a boolean
flag. With that you could then check in the close()
method if the connection should be closed peacefully or it should rollback:
public class OurConnectionClass implements AutoCloseable{
private boolean committed; // initialized to false
public void commit(){
// commit
committed = true;
}
public void close() throws Exception{
if(!committed){
// rollback
}
}
}
Upvotes: 3