Spring事务启用异常求助:javax.persistence.TransactionRequiredException
Hey there, let's figure out why your Spring MVC transactions aren't kicking in. From the partial config you shared, here are the most common culprits and actionable fixes to try:
1. You're missing transaction annotation-driven configuration
This is the #1 reason transactions fail to activate. Spring needs explicit instruction to recognize @Transactional annotations.
First, make sure your XML config includes the tx namespace, then add the annotation-driven tag:
<!-- Add these to your root beans element --> xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" ... http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" <!-- Then enable annotation-driven transactions --> <tx:annotation-driven transaction-manager="transactionManager"/>
2. No transaction manager bean is defined
You've set up the LocalContainerEntityManagerFactoryBean, but Spring needs a transaction manager to coordinate transactions with it. Add a JpaTransactionManager bean:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="ecareEMF"/> </bean>
3. Issues with @Transactional usage
Double-check these common mistakes:
- You applied
@Transactionalto a private method: Spring AOP doesn't proxy private methods, so the annotation will be ignored. Move the annotation to a public method, or use AspectJ weaving if you need private method transactions. - The class with
@Transactionalisn't a Spring-managed bean: Make sure the class is annotated with@Service,@Component, or another stereotype annotation, and that it's within theru.tsystemspackage scanned by<context:component-scan>. - You're catching exceptions without rethrowing them: If you catch a checked exception (like
SQLException) and don't rethrow it, Spring won't trigger a rollback. Use@Transactional(rollbackFor = Exception.class)to force rollback on all exceptions, or rethrow the exception.
4. Full config example (filling in gaps)
Here's how your complete config should look to ensure transactions work:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="ru.tsystems"/> <!-- Example data source config with HikariCP --> <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ecare_db"/> <property name="username" value="your_db_username"/> <property name="password" value="your_db_password"/> </bean> <bean id="ecareEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="ru.tsystems.persistence.entity"/> <!-- Add JPA vendor adapter (example for Hibernate) --> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true"/> <property name="generateDdl" value="true"/> <property name="databasePlatform" value="org.hibernate.dialect.MySQL8Dialect"/> </bean> </property> </bean> <!-- JPA Transaction Manager --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="ecareEMF"/> </bean> <!-- Enable annotation-driven transactions --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
5. Hidden gotcha: Internal method calls
If you're calling a @Transactional method from another method in the same class, Spring's proxy-based AOP won't trigger the transaction. For example:
@Service public class UserService { public void updateUser() { this.doTransactionalUpdate(); // Transaction won't work here } @Transactional public void doTransactionalUpdate() { // DB operations } }
Fix this by moving the transactional method to a separate Spring bean, or use AopContext.currentProxy() to call the method via the proxy.
内容的提问来源于stack exchange,提问作者Nikita Mikhailov

