I have an abstract class and two sub classes that extend it. I have the following in spring config file
<bean id="importConfigFile" class="xxx.ImportConfigFiles" parent="parentImportFile"></bean>
<bean id="importFile" class="xxx.ImportUMTSKPIFiles" parent="parentImportFile"></bean>
<bean id="parentImportFile" name="parentImportFile" class="xxx.ImportUMTSFiles" abstract="true"></bean>
<tx:annotation-driven transaction-manager="transactionManager" />
In my abstract class I have the following methods
public void importDataToDB(){
//all the good stuff goes in here
}
@Transactional
public void executeInsertUpdateQuery(){
//all the good stuff goes in here
}
My java code
ImportConfigFiles importConfigFiles = (ImportConfigFiles)context.getBean("importConfigFile");
importConfigFiles.setFileLocation(destPath);
importConfigFiles.importDataToDB();
This does not work. executeInsertUpdateQuery() executes just one native sql query. If I put @Transactional on imortDataToDB() it works but then it makes my transaction huge since inside that method I loop through all the rows in a file and insert the records in db.
The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.
The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction".
The TransactionStatus interface provides a simple way for transactional code to control transaction execution and query transaction status. Sr.No. This method returns whether this transaction internally carries a savepoint, i.e., has been created as nested transaction based on a savepoint.
Transactional annotation provides the application the ability to declaratively control transaction boundaries on CDI managed beans, as well as classes defined as managed beans by the Java EE specification, at both the class and method level where method level annotations override those at the class level.
This is one of the major pitfalls in Spring - if you call @Transactional
-method from non-transactional method in the same class, the @Transactional
is ignored (unless you use AspectJ weaving). This is not Spring problem per se - the EJB has the same shortcomings.
Unfortunately with interface-based and class-based proxies all you can do is to split your class in two:
public class BeanA() {
@Resource
private BeanB b;
public void importDataToDB(){
b.executeInsertUpdateQuery();
}
}
public class BeanB {
@Transactional
public void executeInsertUpdateQuery(){
//all the good stuff goes in here
}
}
The whole hustle is caused by the internal implementation of AOP proxies in Spring. With the code above new transaction will be started every time you call b.executeInsertUpdateQuery()
from non-transactional BeanA
.
I wrote about it on my blog Spring pitfalls: proxying, Spring AOP riddle and Spring AOP riddle demystified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With