[英]Spring @Transactional annotation not working
Currently I'm making a Spring course on Udemy and I'm having problems with the @Transactional
annotation in the CustomerDAO
class. 目前,我正在上有关Udemy的春季课程,并且在
CustomerDAO
类中使用@Transactional
批注时遇到问题。 I'm using Maven and Java 8. It simply doesn't works, here is the response from Tomcat 9: 我正在使用Maven和Java8。它根本不起作用,这是Tomcat 9的响应:
HTTP Status 500 – Internal Server Error
Type Exception Report
Message Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
Description The server encountered an unexpected condition that prevented it from fulfilling the request.
Exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1013)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause
javax.persistence.TransactionRequiredException: no transaction is in progress
org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3552)
org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1444)
org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1440)
org.springframework.orm.hibernate5.SessionFactoryUtils.flush(SessionFactoryUtils.java:147)
org.springframework.orm.hibernate5.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:95)
org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:96)
org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:922)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:730)
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
net.matbm.springlearn.dao.CustomerDAO$$EnhancerBySpringCGLIB$$6447db19.getCustomers(<generated>)
net.matbm.springlearn.dao.CustomerDAO$HOTSWAPAGENT_$$FastClassBySpringCGLIB$$466694ed.invoke(<generated>)
org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
HotswapSpringCallback_1796692748.intercept(HotswapSpringCallback_1796692748.java)
net.matbm.springlearn.dao.CustomerDAO$HOTSWAPAGENT_$$EnhancerBySpringCGLIB$$feb7e678.getCustomers(<generated>)
net.matbm.springlearn.service.CustomerService.getAllCustomers(CustomerService.java:16)
net.matbm.springlearn.controller.CustomerController.listCustomers(CustomerController.java:26)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Note The full stack trace of the root cause is available in the server logs.
I've already seen another stack overflow posts and none of them helped me solve the issue! 我已经看到了另一个堆栈溢出的帖子,但是没有一个可以帮助我解决问题! Currently this is the second consecutive day I'm struggling with this issue.
目前,这是我连续第二天在努力解决这个问题。 It simply doesn't works.
它根本不起作用。 I already tried to create a
servlet-context.xml
to "separate the contexts" but it doesn't solved the issue. 我已经尝试创建一个
servlet-context.xml
来“分离上下文”,但是并不能解决问题。 Here is the source code related to the project: 这是与项目相关的源代码:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>spring-mvc-demo</display-name>
<!-- Spring MVC Configs -->
<!-- Step 1: Configure Spring MVC Dispatcher Servlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Step 2: Set up URL mapping for Spring MVC Dispatcher Servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
spring.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Add support for component scanning -->
<context:component-scan base-package="net.matbm.springlearn.config"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
</beans>
net.matbm.springlearn.config.AppConfig.java
package net.matbm.springlearn.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.PooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.beans.PropertyVetoException;
import java.util.Properties;
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("net.matbm.springlearn")
public class AppConfig implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
@Bean(destroyMethod = "close")
public PooledDataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource source = new ComboPooledDataSource();
source.setDriverClass("org.postgresql.Driver");
source.setJdbcUrl("jdbc:postgresql://localhost/java");
source.setUser("java");
source.setPassword("java");
source.setMinPoolSize(5);
source.setMinPoolSize(20);
source.setMinPoolSize(3000);
return source;
}
@Bean
public LocalSessionFactoryBean sessionFactory() throws PropertyVetoException {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("net.matbm.springlearn.model");
factoryBean.setHibernateProperties(hibernateProperties());
return factoryBean;
}
@Bean
public PlatformTransactionManager transactionManager() throws PropertyVetoException {
HibernateTransactionManager manager = new HibernateTransactionManager();
manager.setSessionFactory(sessionFactory().getObject());
return manager;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("resources/");
}
private Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "create");
return hibernateProperties;
}
}
net.matbm.controller.CustomerController.java
package net.matbm.springlearn.controller;
import net.matbm.springlearn.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/customer")
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@RequestMapping()
public String home() {
return "customer/home";
}
@RequestMapping("/list")
public String listCustomers(Model model) {
model.addAttribute("customers", customerService.getAllCustomers());
return "customer/list-customers";
}
}
net.matbm.service.CustomerService.java
package net.matbm.springlearn.service;
import net.matbm.springlearn.dao.CustomerDAO;
import net.matbm.springlearn.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CustomerService {
@Autowired
private CustomerDAO customerDAO;
public List<Customer> getAllCustomers() {
return customerDAO.getCustomers();
}
}
net.matbm.dao.CustomerDAO.java
package net.matbm.springlearn.dao;
import net.matbm.springlearn.model.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Repository
public class CustomerDAO {
@Autowired
private SessionFactory sessionFactory;
@Transactional
public List<Customer> getCustomers() {
Session session = sessionFactory.getCurrentSession();
Query<Customer> query =
session.createQuery("from Customer", Customer.class);
return query.getResultList();
}
}
net.matbm.model.Customer.java
package net.matbm.springlearn.model;
import javax.persistence.*;
@Entity
@Table(name = "customer")
public class Customer {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
public Customer() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
'}';
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.matbm</groupId>
<artifactId>SpringLearn</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Spring Learn</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>5.1.3.RELEASE</spring.version>
<jdk.version>1.8</jdk.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.7.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.3.7.Final</version>
</dependency>
</dependencies>
<build>
<finalName>SpringMaven</finalName>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>TomcatServer</server>
<path>/</path>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Thanks in advance. 提前致谢。
in service layer you used the the @Autowired Annotation and DAO Layer you used the @Tranjaction annotation so thats why its giving an error. 在服务层中,您使用了@Autowired批注,而DAO层中使用了@Tranjaction批注,因此这就是为什么会出错的原因。
so use the @Transactional Annotation in service layer and use the @Autowired annotation in DAO Layer 因此请在服务层中使用@Transactional批注,并在DAO层中使用@Autowired批注
Make change in Service layer shown below 在下面显示的服务层中进行更改
import net.matbm.springlearn.dao.CustomerDAO;
import net.matbm.springlearn.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CustomerService {
@Autowired
private CustomerDAO customerDAO;
@Transactional
public List<Customer> getAllCustomers() {
return customerDAO.getCustomers();
}
}
Make change in DAO layer Shown below 更改DAO图层,如下所示
package net.matbm.springlearn.dao;
import net.matbm.springlearn.model.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Repository
public class CustomerDAO {
@Autowired
private SessionFactory sessionFactory;
@Override
public List<Customer> getCustomers() {
Session session = sessionFactory.getCurrentSession();
Query<Customer> query =
session.createQuery("from Customer", Customer.class);
return query.getResultList();
}
}
As per exception looks like your transactionManager config is not correct. 作为例外,看起来您的transactionManager配置不正确。
Any specific reason for using PlatformTransactionManager
?? 使用
PlatformTransactionManager
任何特定原因?
If not use this config 如果不使用此配置
Working config for Transaction usinHibernatete 4 looks like this 事务usinHibernatete 4的工作配置如下所示
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-mysql.properties" })
@ComponentScan({ "org.baeldung.spring.persistence" })
public class PersistenceConfig {
@Autowired
private Environment env;
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(
new String[] { "org.baeldung.spring.persistence.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
public DataSource restDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
@Bean
@Autowired
public HibernateTransactionManager transactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager txManager
= new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties hibernateProperties() {
return new Properties() {
{
setProperty("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
setProperty("hibernate.dialect",
env.getProperty("hibernate.dialect"));
setProperty("hibernate.globally_quoted_identifiers",
"true");
}
};
}
}
Else if you want a solution for PlatformTransactionManager
否则,如果您需要
PlatformTransactionManager
的解决方案
After changing the CustomerDAO
the transaction started working: 更改
CustomerDAO
,交易开始工作:
@Repository
public class CustomerDAOImpl implements CustomerDAO {
@PersistenceContext
private EntityManager entityManager;
public List<Customer> getCustomers() {
Query<Customer> query =
(Query<Customer>) entityManager.createQuery("from Customer", Customer.class);
return query.getResultList();
}
}
Using @PersistenceContext
instead of a SessionFactory
resolved the issue. 使用
@PersistenceContext
而不是SessionFactory
解决了该问题。 I don't know why. 我不知道为什么
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.