我有一个问题,Spring 将 DAO 对象的代理注入(inject)到服务中,但该服务被注入(inject)到 Controller 中,它是具体类。这不允许我使用服务范围的事务并分别为每个 DAO 调用启动事务。这是我期望的行为。
配置:
Controller 是带有@Controller 注解和构造函数DI 的类。
服务:
@Component @Transactional public class UserServiceImpl implements UserService { ...}
Dao:
@Component @Transactional public class UserDaoImpl implements UserDao {
JPA Config:
<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 />
有人知道为什么会这样吗?
最佳答案
很可能是您的 UserServiceImpl
已创建 in the servlet context错误-请检查context:component-scan
只检查 Controller
的表达式类包含在那里。
参见 @Service are constructed twice 有关组件扫描过滤器的示例。
例如,如果事务管理器 bean 和 <tx:annotation-driven>
在 root web app context 中声明,那么事务代理将仅为根应用程序上下文中的 beans 创建(来自 Spring Documentation ):
BeanPostProcessor interfaces are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanPostProcessor in one container, it will only do its work on the beans in that container. Beans that are defined in one container are not post-processed by a BeanPostProcessor in another container, even if both containers are part of the same hierarchy.
不太可能是用户服务的事务配置被配置为使用另一个事务管理器(或另一个默认传播),但在那种情况下 TransactionInterceptor
调用将出现在 DAO 方法的堆栈跟踪中。
绝对可以@Transactional
在 Spring 的 DAO 类上,如果您了解自己在做什么 - 存储库或 DAO 无法打开事务的想法来自黑暗时代,当时您必须创建样板代码来打开事务并且很难管理事务实例(而且您无法确定交易是如何管理的)。但是当你使用声明式配置时,事情并没有那么糟糕。 Spring 提倡约定优于配置的风格,其中大多数方法使用 Propagation.REQUIRED
交易模式。 Spring Propagation.REQUIRED
是用 @Transactional
修饰方法时的默认模式(此传播被硬编码为 @Transactional
注释声明),这意味着新的逻辑事务映射到相同的物理事务,因此使用 @Transactional
装饰您的 DAO 类是无害的。
参见 http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html#tx-propagation供Spring中事务传播引用
在 Spring Data JPA 中(我很确定他们知道自己在做什么),例如,CRUD methods on repository instances are transactional by default .这在某些情况下可能很有用,该机制与 Hibernate 允许您从 Session
中获取()一些任意对象时的机制相同。用于在不声明显式事务的情况下显示(当然这并不意味着框架以某种方式设法在没有事务的情况下进行 - 在这种情况下它是隐含的)。
关于java - Spring正在注入(inject)具体类而不是代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14587134/