即使 @Transactional 放置在服务层中,Spring boot JPA 存储库也会提交代码

Posted

技术标签:

【中文标题】即使 @Transactional 放置在服务层中,Spring boot JPA 存储库也会提交代码【英文标题】:Spring boot JPA repository committing code even if @Transactional placed in Service layer 【发布时间】:2020-06-26 16:21:53 【问题描述】:

参见下面的 Spring Boot 代码

我使用过 JPA 存储库。

    控制器。 服务。 存储库

基础控制器

package com.controller;

import com.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BaseController 

    @Autowired
    private StudentService studentService;

    @GetMapping(value = "/addStudent", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<String> base() 


        studentService.save();

        return new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
    


StudentService.java

package com.service;

import com.model.Student;
import com.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("studentService")
public class StudentServiceImpl implements StudentService 

    @Autowired
    private StudentRepository studentRepository;

    @Override
    @Transactional
    public Student save() 

        Student student = new Student();
        student.setFirstName("ABC");
        student.setLastName("PQR");
        studentRepository.save(student);

        int i = 10 / 0;  //Error code

        return student;
    


StudentRepository

package com.repository;

import com.model.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository("studentRepository")
public interface StudentRepository extends CrudRepository<Student, Long> 

    public List<Student> findAll();



Application.properties

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
#maximum number of milliseconds that a client will wait for a connection
spring.datasource.hikari.connection-timeout = 20000
#minimum number of idle connections maintained by HikariCP in a connection pool
spring.datasource.hikari.minimum-idle= 10
#maximum pool size
spring.datasource.hikari.maximum-pool-size= 10
#maximum idle time for connection
spring.datasource.hikari.idle-timeout=10000
# maximum lifetime in milliseconds of a connection in the pool after it is closed.
spring.datasource.hikari.max-lifetime= 1000
#default auto-commit behavior.
spring.datasource.hikari.auto-commit =false

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.jdbcUrl=jdbc:mysql://localhost:3306/demo?autoReconnect=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.properties..hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=update

从 StudentRepository 执行 save 方法后,数据被插入 立即进入数据库。没有回滚或任何其他隔离级别 即使有错误代码,也可以在 StudentServiceImpl.java 中工作。 我尝试设置"spring.datasource.hikari.auto-commit =true" 设置值true,将@Transaction 放在StudentServiceImpl.java 类的顶部,但仍然没有用。

【问题讨论】:

Spring 没有检测到/您期望在这里出现什么样的错误? 【参考方案1】:

这可能是因为 Open Jpa in View 的行为。 在属性文件中写入以下行:

spring.jpa.open-in-view=false

看看this if you want to know more。

【讨论】:

【参考方案2】:
    您不需要弄乱 任何 hikari 设置,当然也不需要使用 autoCommit(true),因为这会禁用事务。 删除所有这些属性。 代码中的“错误”在哪里? Spring 在抛出 未经检查的异常(未检查的异常或错误)时回滚,我在您的代码中看不到。 您期望什么行为?我觉得很好。

【讨论】:

以上是关于即使 @Transactional 放置在服务层中,Spring boot JPA 存储库也会提交代码的主要内容,如果未能解决你的问题,请参考以下文章

在哪里放置@Transactional?在接口规范或实现中? [复制]

N 层服务层验证显示表示层中的业务逻辑错误

CALayer 帧值即使在从超级层中移除后也会导致动画

Spring中层之间的@Transaction注解

service层中数据异常时回滚

在哪里放置加载和保存功能