I use the class below to devise a strategy/code structure to perform several operations sequentially, from a single method, but have each operation performed in a separate transaction.
It doesn't seem to work, however. What I want is that whatever happens inside actualTransaction() is rolled back if there's an exception in that method. What I expect is that when entering doSeparateTransaction() a transaction should be started, which should be commited in case the call to actualTransaction completes without an error, and rolled back if any error is generated in that function. What actually happens is quite different.
A transaction is started only inside the method call in line 017. This method being called on __provider actually is the first one, down the call hierarchy, wrapped by a proxy which I can see in the call stack is named something like TransactionWrapper. How come? I have annotated all classes with @Transactional, provided the propagation which I deemed right for each point, and I raise an exception which I do not catch in the caling method, which also has a @Transactional annotation.
In the static void main() from where I call entryPoint() I obtain the bean from a Spring context, with __provider already properly initialized by the context. The context being able to initialize __provider based on explicit bean property definition is the only reason there are a getter and a setter provided for __provider.
I have read the forums, and while I was able to find posts on transactions and rollback, I was not able to find something pertinent to my problem.
I can provide additional files or log output, if useful, I just don't know what is indeed useful, so I'd rather upload only what's required after it is asked for than create a uselessly long post right from the start.
Code:000 @Transactional 001 public class WithDistinctTransactionMethod implements IWithDistinctTransaction 002 { 003 private dbOperationsProvider __provider; 004 public dbOperationsProvider getProvider() 005 { 006 return __provider; 007 } 008 public void setProvider(dbOperationsProvider provider) 009 { 010 __provider = provider; 011 } 012 @Transactional 013 private void actualTransaction(int toWrite) 014 { 015 String arrayName = "transaction " + toWrite; 016 Object[] parameters = {toWrite}; 017 __provider.writeQueryParameters(arrayName, parameters); 018 if (toWrite % 2 == 0) 019 throw new RuntimeException("Intentionally thrown to fail transaction"); 020 } 021 @Override 022 @Transactional(propagation = Propagation.REQUIRES_NEW) 023 public void doSeparateTransaction(int toWrite) 024 { 025 actualTransaction(toWrite); 026 } 027 @Override 028 @Transactional(propagation = Propagation.NEVER) 029 public void entryPoint() 030 { 031 for (int i = 0; i < 10; i++) 032 { 033 try 034 { 035 doSeparateTransaction(i); 036 } 037 catch(RuntimeException ex) 038 { 039 System.out.println("Exception for " + i); 040 } 041 } 042 } 043 }


Reply With Quote
We were having transactions configured redundantly, using both <tx:advice /> in the XML file, and <tx:annotation-driven />, which created a mess. Furthermore, we had @Transactional without a specified propagation on each and every possible method in our classes, which caused the mess to be even bigger - everything was transactional, and everything was using the same transaction, and even if someone started a new transaction in between, everything outside the particular method starting the transaction was still executing in the old transaction. Even more, stupid me was assuming that MySQL MEMORY tables are transactional - which they aren't.
