Spring introduces concrete class instead of proxy

I have a problem when Spring injects a proxy for a DAO object into a service, but this service is injected into the controller, this is a specific class. This does not allow me to use the transaction throughout the service and starts the transaction for each DAO call separately. It seems like I would expect.

Configuration:

A controller is a class with @Controller annotation and a DI constructor.

Services:

  @Component
 @Transactional
 public class UserServiceImpl implements UserService {...}

Dao:

  @Component
 @Transactional
 public class UserDaoImpl implements UserDao {

JPA configuration:

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > <property name="dataSource" ref="dataSource"/> <property name="persistenceUnitName" value="xxxPersistenceUnit"/> <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> </bean> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <tx:annotation-driven /> 

Does anyone know why this is happening?

+4
source share
4 answers

Most likely your UserServiceImpl is created in the servlet context by mistake - check the context:component-scan expressions to verify that only the Controller classes are included there.

See @ Service created twice for examples of component scan filters.

For example, if the transaction manager bean and <tx:annotation-driven> declared in the context of the root web application , then transaction proxies will be created only for beans in the root context of the application (from the Spring Documentation ):

The BeanPostProcessor interfaces are bound to a container. This is only if you use container hierarchies. If you define a BeanPostProcessor in one container, it will only do work on beans in that container. beans that are defined in one container are not processed by the BeanPostProcessor in another container, even if both containers are part of the same hierarchy.

It is less likely that the transactional configuration of the user service is configured to use a different transaction manager (or other default distribution), but in this case, the TransactionInterceptor call will be present in the stack trace of the DAO method.

It’s absolutely normal to have @Transactional on DAO classes in Spring, if you understand what you are doing - the idea that the repository or DAO cannot open transactions comes from the dark times when you had to create boilerplate code to open transactions, and it was difficult to manage transaction instances (and you couldn't be sure how transactions were managed). But when you use declarative configuration, everything is not so bad. Spring supports a configuration convention style in which most methods use the Propagation.REQUIRED transaction mode. Spring Propagation.REQUIRED uses the default mode when you decorate methods using @Transactional (this distribution is strictly indicated in the @Transactional annotation @Transactional ), this means that the new logical transaction is mapped to the same physical transaction, therefore decorating your Classes DAOs with @Transactional harmless.

See http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html#tx-propagation for a link to distributing a transaction in Spring

In Spring Data JPA (I'm sure they know what they are doing), for example, CRUD methods on repository instances are transactional by default . This can be useful in some cases, the mechanism is the same as when Hibernate allows you to get () some arbitrary objects from Session to display without declaring an explicit transaction (of course, this does not mean that the infrastructure somehow leaves without a transaction - this is implied in in this case).

+5
source

I have a bit of trouble understanding what you are saying, but you seem to be surprised to get a new transaction for every DAO call, not just from a service call. Unfortunately, this is exactly what you indicated by putting "@Transactional" on the DAO class. Your DAO should not be transactional, at least if you follow the usual pattern. If you understand correctly, you should remove the @Transactional annotation in your DAO class.

+2
source

Other respondents are true that you should not annotate your DAO as @Transactional , but to really understand what is happening, you should refer to the Transaction Distribution Section in the Spring Reference Guide . The default distribution when using @Transactional is REQUIRES_PROPAGATION , so check this out specifically.

Your question is not so specific, so I’m not sure exactly what you are looking for.

Edit: After re-reading your question, it is possible that there might be a problem with your component scan. Make sure your <tx:annotation-driven /> is in the same application context in which you are scanning your classes of service.

+1
source

You should not use this @Transactional annotation in your DAO object. You define it in your Service and provide that all your DAO methods called inside the service method are executed within the same transaction, which seems to be exactly what you want when you say “transaction across the service”, right

Also, as suggested, you can change your annotation from "@Component" to "@Service" in UserServiceImpl and to "@Repository" in UserDaoImpl.

Sincerely.

0
source

All Articles