事务注释在Spring Boot中不起作用

@Transactional在Spring Boot中不起作用。

Application.java:

@EnableTransactionManagement(proxyTargetClass=true) @SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class}) public class Application { @Autowired private EntityManagerFactory entityManagerFactory; public static void main(String[] args) { System.out.println("--------------------------- Start Application ---------------------------"); ApplicationContext ctx = SpringApplication.run(Application.class, args); } @Bean public SessionFactory getSessionFactory() { if (entityManagerFactory.unwrap(SessionFactory.class) == null) { throw new NullPointerException("factory is not a hibernate factory"); } return entityManagerFactory.unwrap(SessionFactory.class); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); em.setPackagesToScan(new String[] { "com.buhryn.interviewer.models" }); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(additionalProperties()); return em; } @Bean public DataSource dataSource(){ DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.postgresql.Driver"); dataSource.setUrl("jdbc:postgresql://localhost:5432/interviewer"); dataSource.setUsername("postgres"); dataSource.setPassword("postgres"); 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 additionalProperties() { Properties properties = new Properties(); properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); properties.setProperty("hibernate.show_sql", "false"); properties.setProperty("hibernate.format_sql", "false"); properties.setProperty("hibernate.hbm2ddl.auto", "create"); properties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext"); return properties; } } 

CandidateDao.java

 import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @Repository public class CandidateDao implements ICandidateDao{ @Autowired SessionFactory sessionFactory; protected Session getCurrentSession(){ return sessionFactory.getCurrentSession(); } @Override @Transactional public CandidateModel create(CandidateDto candidate) { CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone()); getCurrentSession().save(candidateModel); return candidateModel; } @Override public CandidateModel show(Long id) { return new CandidateModel( "new", "new", "new", "new"); } @Override public CandidateModel update(Long id, CandidateDto candidate) { return new CandidateModel( "updated", candidate.getLastName(), candidate.getEmail(), candidate.getPhone()); } @Override public void delete(Long id) { } } 

服务类

 @Service public class CandidateService implements ICandidateService{ @Autowired ICandidateDao candidateDao; @Override public CandidateModel create(CandidateDto candidate) { return candidateDao.create(candidate); } @Override public CandidateModel show(Long id) { return candidateDao.show(id); } @Override public CandidateModel update(Long id, CandidateDto candidate) { return candidateDao.update(id, candidate); } @Override public void delete(Long id) { candidateDao.delete(id); } } 

Controller.class

 @RestController @RequestMapping(value = "/api/candidates") public class CandidateController { @Autowired ICandidateService candidateService; @RequestMapping(value="/{id}", method = RequestMethod.GET) public CandidateModel show(@PathVariable("id") Long id) { return candidateService.show(id); } @RequestMapping(method = RequestMethod.POST) public CandidateModel create(@Valid @RequestBody CandidateDto candidate, BindingResult result) { RequestValidator.validate(result); return candidateService.create(candidate); } @RequestMapping(value="/{id}", method = RequestMethod.PUT) public CandidateModel update(@PathVariable("id") Long id, @Valid @RequestBody CandidateDto candidate, BindingResult result) { RequestValidator.validate(result); return candidateService.update(id, candidate); } @RequestMapping(value="/{id}", method = RequestMethod.DELETE) public void delete(@PathVariable("id") Long id) { candidateService.delete(id); } } 

当我在DAO系统中调用create方法时抛出exception

 org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: save is not valid without active transaction; nested exception is org.hibernate.HibernateException: save is not valid without active transaction org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868) javax.servlet.http.HttpServlet.service(HttpServlet.java:644) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) javax.servlet.http.HttpServlet.service(HttpServlet.java:725) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:291) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 

我的Gradle文件:

 buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE") } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'spring-boot' jar { baseName = 'interviewer' version = '0.1.0' } repositories { mavenCentral() } sourceCompatibility = 1.8 targetCompatibility = 1.8 dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-actuator") compile("org.codehaus.jackson:jackson-mapper-asl:1.9.13") compile("com.google.code.gson:gson:2.3.1") compile("org.springframework.data:spring-data-jpa:1.8.0.RELEASE") compile("org.hibernate:hibernate-entitymanager:4.3.10.Final") compile("postgresql:postgresql:9.1-901-1.jdbc4") compile("org.aspectj:aspectjweaver:1.8.6") testCompile("org.springframework.boot:spring-boot-starter-test") } task wrapper(type: Wrapper) { gradleVersion = '2.3' } 

并链接到git存储库: https : //github.com/Yurii-Buhryn/interviewer

首先,您使用的是Spring Boot,然后使用Spring Boot,让它自动为您配置。 它将配置数据源,entitymanagerfactory,事务管理器等。

接下来你使用了错误的事务管理器,你正在使用JPA所以你应该使用JpaTransactionManager而不是HibernateTransactionManager ,因为已经为你配置了你可以简单地删除它的bean定义。

其次你的hibernate.current_session_context_class搞乱了正确的tx集成删除它。

使用auto-config

考虑到所有这些因素后,您基本上可以将Application类减少到以下内容。

 @SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class}) @EntityScan("com.buhryn.interviewer.models") public class Application { public static void main(String[] args) { System.out.println("--------------------------- Start Application ---------------------------"); ApplicationContext ctx = SpringApplication.run(Application.class, args); } @Bean public SessionFactory sessionFactory(EntityManagerFactory emf) { if (emf.unwrap(SessionFactory.class) == null) { throw new NullPointerException("factory is not a hibernate factory"); } return emf.unwrap(SessionFactory.class); } } 

接下来在src/main/resources包含以下内容的application.properties

 # DataSource configuration spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.username=postgres spring.datasource.password=postgres spring.datasource.url=jdbc:postgresql://localhost:5432/interviewer # General JPA properties spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect spring.jpa.show-sql=false # Hibernate Specific properties spring.jpa.properties.hibernate.format_sql=false spring.jpa.hibernate.ddl-auto=create 

这将正确配置数据源和JPA。

使用JPA而不是普通的Hibernate

另一个提示而不是使用普通的hibernate API只是使用JPA,你也可以删除SessionFactory的bean。 只需更改您的dao即可使用EntityManager而不是SessionFactory

 @Repository public class CandidateDao implements ICandidateDao{ @PersistenceContext private EntityManager em; @Override @Transactional public CandidateModel create(CandidateDto candidate) { CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone()); return em.persist(candidateModel); } @Override public CandidateModel show(Long id) { return new CandidateModel( "new", "new", "new", "new"); } @Override public CandidateModel update(Long id, CandidateDto candidate) { return new CandidateModel( "updated", candidate.getLastName(), candidate.getEmail(), candidate.getPhone()); } @Override public void delete(Long id) { } } 

添加Spring Data JPA

如果你真的想要将Spring Data JPA添加到混合中并完全删除你的DAO并只留下一个界面。 你现在拥有的东西将被转移到服务类(它属于恕我直言)。

整个存储库

 public interface ICandidateDao extends JpaRepository {} 

修改后的服务(现在也应该是事务性的,所有业务逻辑都在服务中)。

 @Service @Transactional public class CandidateService implements ICandidateService{ @Autowired ICandidateDao candidateDao; @Override public CandidateModel create(CandidateDto candidate) { CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone()); return candidateDao.save(candidate); } @Override public CandidateModel show(Long id) { return candidateDao.findOne(id); } @Override public CandidateModel update(Long id, CandidateDto candidate) { CandidateModel cm = candidateDao.findOne(id); // Update values. return candidateDao.save(cm); } @Override public void delete(Long id) { candidateDao.delete(id); } } 

现在,您还可以删除SessionFactory的bean定义,将Application简化为main方法。

 @SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class}) @EntityScan("com.buhryn.interviewer.models") public class Application { public static void main(String[] args) { System.out.println("--------------------------- Start Application ---------------------------"); ApplicationContext ctx = SpringApplication.run(Application.class, args); } } 

所以我强烈建议使用框架而不是尝试解决框架。 因为这将真正简化您的开发人员。

依赖

最后,我建议从依赖项中删除spring-data-jpa依赖项,然后使用starter。 AspectJ使用AOP启动器也是如此。 此外,不再支持jackson 1,因此添加依赖项不会添加任何内容

 dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-actuator") compile("org.springframework.boot:spring-boot-starter-data-jpa") compile("org.springframework.boot:spring-boot-starter-aop") compile("com.google.code.gson:gson:2.3.1") compile("org.hibernate:hibernate-entitymanager:4.3.10.Final") compile("postgresql:postgresql:9.1-901-1.jdbc4") testCompile("org.springframework.boot:spring-boot-starter-test") }