Spring Jdbc declarative transactions created but do nothing

I tried setting up declarative transaction management in my Spring-based web application and it refuses to work with me.

I have two main problems:

  • Setting defaultAutoCommit to false on our data source (what we need for our application) causes all requests to be rolled back, with or without transactions.
  • Transactions are generated, as well as proxy classes, as well as transactional methods, but transactions are not used.

The first problem is rather perplexing, since each individual request is returned to the database. This also includes SELECT statements. What can lead to rollback of each request in a database?

Regarding the second issue, my transaction management configuration is described below:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd" default-autowire="byName"> <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- the transactional semantics... --> <tx:attributes> <!-- other methods use the default transaction settings (see below) --> <tx:method name="*" rollback-for="Exception" /> </tx:attributes> </tx:advice> <!-- ensure that the above transactional advice runs for any execution of an operation defined by a service in the service package --> <aop:config> <aop:pointcut id="serviceOperations" expression="execution(* foo.bar.service.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations"/> </aop:config> <!-- similarly, don't forget the PlatformTransactionManager --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="defaultAutoCommit" value="false" /> </bean> <bean id="fooService" class="foo.bar.service.FooService" /> <bean id="barService" class="foo.bar.service.BarService" /> <bean id="zapService" class="foo.bar.service.ZapService" /> </beans> 

Of all the training programs and forums that I visited in an attempt to solve this problem, I believe that my configuration should be correct. However, I do not fully understand aop and spring transactions, so I might have something important.

As mentioned above, I can track my logs and view proxies as well as transactional methods created for my classes of service. However, when I actually launch the application and trace through the logs, I do not see any statements related to the DataSourceTransactionManager or generated transactions, executed, canceled, etc.

It seems to me that nothing really starts up, and I'm terribly confused, since I followed a lot of different textbooks and tried it in different ways, but it always ends with this situation.

I am also sure that my log4j properties are correctly configured to receive messages from the DataSourceTransactionManager, but I provide them below to make sure that this is not just a registration error on my side.

My log4j is configured with the following loggers to try and track transactions:

 log4j.logger.org.springframework=INFO, file log4j.logger.org.springframework.jdbc.datasource=DEBUG, file log4j.logger.org.springframework.transaction=DEBUG, file 

Note. At some point, I started the upper logger on DEBUG, and it was there that I checked that service proxies were being created.

Does anyone have an idea of ​​what might happen? I’m pretty stuck at the moment, because I see some parts related to the transactions being created, but I don’t see any signs of any transactions that would be used at all.

Edit

Further information on request from JB Nizet.

My entire application is annotated, so my beans service is annotated using @Service and injected into my controllers through auto-negotiation by name.

The following is an example of one of my service classes (the names have been changed but will be displayed in my context.xml application).

 @Service("zapService") public class ZapService { /** * Data access object which performs the database look up */ private ZapDAO zapDAO; /** * Add the given zap to the database * * @param zap a populated zap */ public void processNewZap(Zap zap) { zapDAO.processNewZap(zap); } } 

As you can see, my service classes are just proxies between controller classes and dao classes. DAO is where I actually handle database connections.

I believe that I read somewhere that providing services to transactional rather than dao classes was the preferred practice when dealing with transactions. Please correct me if I am wrong.

The ZapDAO class is described below.

 @Repository("zapDAO") public class ZapDAO { /** * Log4j logger for this class */ Logger logger = Logger.getLogger(ZapDAO.class); /** * Spring jdbc object to handle interacting with the database */ private JdbcTemplate jdbcTemplate; public void processNewZap(Zap zap) { ... query constructing logic ... this.jdbcTemplate.update(INSERT_ZAP_QUERY_SQL); } public void setDataSource(DataSource dataSource) { Assert.notNull(dataSource, "You must supply a valid data source"); this.jdbcTemplate = new JdbcTemplate(dataSource); } } 

I use jdbcTemplate to handle my connections and requests.

+2
source share
1 answer

So, after several hours of searching, debugging, and tearing my hair out, I finally stumbled upon this little stone that provided all the answers.

I would never suspect something like this in this, but after the steps described in the link above worked fine.

Inside my dispatch-servlet.xml, I initially declared my component scan as follows:

 <context:component-scan base-package="foo.bar"/> 

What is the parent package for my entire application beans. So, as described in the link above, Spring rewrites my beans transactional service from applicationContext.xml using the beans service from dispatcher-servlet.xml, which does not know about transactions.

All I did was split the above component scan to scan only those folders that contained non-transactional beans.

 <context:component-scan base-package="foo.bar.controller"/> <context:component-scan base-package="foo.bar.model"/> <context:component-scan base-package="foo.bar.service.display"/> <context:component-scan base-package="foo.bar.service.security"/> <!-- foo.bar.service gets scanned in applicationContext.xml and includes transactions so we must make sure to not include it here. The transactional beans will be overridden in that case --> 

After that, my transactions worked exactly as expected, and I finally saw the traces of transactions and the DataSourceTransactionManager in my log files. This also fixed my first initial problem of automatic rollbacks in the database. I suppose this must have been closely related to the lack of transactions.

+3
source

Source: https://habr.com/ru/post/911332/


All Articles