Java: function call automatically upon scope exit (e.g. C ++ destructors)

To connect mysql, I have a connection object and use the transaction mechanism connection.startTransaction() , connection.commitTransaction() , connection.rollbackTransaction() .

For each startTransaction() there must always be either a call to commitTransaction() or rollbackTransaction() . The absence of such a call or a call to both will break my transaction system.

Therefore, I use them as follows:

 boolean i_am_in_a_transaction=true; try { connection.startTransaction(); ... i_am_in_a_transaction=false; connection.commitTransaction(); } finally { if(i_am_in_a_transaction) { connection.rollbackTransaction(); } } 

This guarantees the declared order of the call, but it is a lot because I have to write these lines wherever I use transactions.

In C ++, I would use a transaction object that checks its destructor if the commit() function was called, otherwise rollback() :

 class Transaction { public: Transaction() :am_in_transaction(false) { } ~Transaction() { if(_am_in_transaction) { rollback(); } } void startTransaction() { _am_in_transaction=true; ...start Transaction... } void commit() { _am_in_transaction=false; ...commit Transaction... } void rollback() { _am_in_transaction=false; ...rollback Transaction... } private: bool _am_in_transaction; } 

Thus, I have logic implemented in one place and I can use it very simply:

 Transaction my_transaction; my_transaction.startTransaction; ... my_transaction.commit(); 

This code is much simpler than the java code above with a try / finally block.

Is there a way to implement this behavior in Java without allocating logic to the caller and forcing him to implement the try / finally block?

Something like a way to automatically call a function at the output of a region will help me.

+4
source share
6 answers

A couple of solutions come to mind ...

As @Dark Falcon notes, this would be a good option for try with resources , which will automatically clear your resources at the end of the attempt. Unfortunately, this is only available in Java 7.

Java classes define a finalize() method that can be called when an object receives garbage collection, but overriding this method will almost never be correct.

I think your only other option, if you are hooked on this idea of ​​“execute code when function returns”, is to use Aspect Oriented Programming . If you are reading some packages, such as AspectJ , or use AOP with Spring, you can create configuration magic to get the code to execute when the function returns, intercepting the call. Here's an example of using Spring AOP to execute different code when returning a function.

+4
source

Something similar (very important) for destructors in C ++ is the finalize() method. The difference is that there is no guarantee when the garbage collector will actually name it, so relying on it is not recommended.

Otherwise, the best you can do is try/finally blocks.

+5
source

There are no destructors in Java. But there are a few “standard” solutions that can help you.

1. Use a template called "template method".

 abstract class Base { public query() { openTransaction(); doQuery(); closeTransaction(); } protected abstract doQuery(); } 

Now you must implement doQuery() in each subclass you create and use it by calling 'query ()' from the base class.

2. Use aspect-oriented programming

3. Use a decorator (wrapper).

4. Use one of the popular ORM infrastructures (Hibernate, iBatis, etc.) that solve all these problems for you and have nothing to do with low-level JDBC materials.

+5
source

If updating for java 7 is an option, there is a new try with resources that will execute the close method in the Closable implementation.

+2
source

I would have only one method and do it only once.

 public static void update(Connection connection, String updateSQL) { PreparedStatement update = null; try { try { connection.startTransaction(); update = connection.prepareStatement(updateString); update.executeUpdate(); } finally { connection.rollbackTransaction(); } connection.commitTransaction(); } finally { if(update != null) update.close(); } } 

later

 update(connection, updateSQL1); update(connection, updateSQL2); // etc. 
+1
source

I know this is an old question, but for others:

You can use an anonymous inner class that implements an interface to do the job, much like the Java Comparator and List comparing mechanisms work. This allows the inner class to be processed as if it were a runtime.

eg. Modifying the original example:

 class Transaction { boolean i_am_in_a_transaction=false; interface AutoRollback { void runQueries() throws Throwable; } void startTransaction() { i_am_in_a_transaction=true; ...start Transaction... } void commit() { i_am_in_a_transaction=false; ...commit Transaction... } void rollback() { i_am_in_a_transaction=false; ...rollback Transaction... } public void execute(AutoRollback work) { try { work.runQueries(); } catch ( Throwable t ) { rollback(); throw t; } } } 

And then an example of how to use it:

 void test() throws WhateverException { Transaction my_transaction; my_transaction.startTransaction(); my_transaction.execute( new AutoRollback() { public void runQueries() throws Throwable { ... perform your queries: can be more than one, complex code, etc. ... ... local variables from the enclosing scope can be used as long as they are final... }}); my_transaction.commit(); } 

If you have Java 8, it gets a lot prettier with lambdas as it retains the new AutoRollback syntax.

If you do not have Java 8, and excessive punctuation is still bothering you, you should be able to use the annotation processor and code injection to make it understandable. Compile-time annotations with the target set to LOCAL_VARIABLE is what you want, then apply it to my_transaction .

... Assuming that your workplace can process annotations like apt or pre-processor, and you want to do so much work for syntactic sugar.

0
source

All Articles