首页 > 解决方案 > 在 Spring Boot 中理解 @Transactional - 尽管异常更改不会在数据库中回滚

问题描述

我试图在春天理解@Transactional - 为了测试它,我创建了一个简单的项目:

模型:

@Entity
public class Model {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    String name;
    Integer age;

    public Model(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

}

存储库:

    @Repository
    public interface ModelRepository extends CrudRepository<Model,Long> {
    }

服务:

@Service
public class ExampleService {

    @Autowired
    private ModelRepository modelRepository;

    @Transactional
    public String doSomething(Integer number) {
        Model test = modelRepository.save(new Model("test", number));
        if(number>4) throw new RuntimeException();

        return test.name;
    }
}

控制器:

@RestController
public class Controller {

    @Autowired
    private ExampleService exampleService;

    @GetMapping(path = "/search/{number}")
    public String search(@PathVariable Integer number){

        return exampleService.doSomething(number);
    }
}

当我去localhost:8080/search/1 - 一切顺利,对象保存在数据库中。

但是当我去localhost:8080/search/10 - 如我所愿 - 它抛出异常,但对象仍然保存在数据库中。

不应该在这里回滚吗?使用 @Transactional 注释的方法是公共的并且在其他 bean 中。

编辑:application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/testtt?createDatabaseIfNotExist=true&useSSL=false&serverTimezone=Europe/Paris
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update

构建.gradle:

plugins {
    id 'org.springframework.boot' version '2.1.7.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '12'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
    compile 'mysql:mysql-connector-java'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

主类:

@SpringBootApplication
public class TransactionalApplication {

    public static void main(String[] args) {
        SpringApplication.run(TransactionalApplication.class, args);
    }

}

标签: javaspringspring-data-jpaspring-data

解决方案


spring、jpa、hibernate 和 c3p0 的配置示例。

    @Configuration
    @ComponentScan("com.company")
    @EnableTransactionManagement
    public class PersistenceConfig {

        @Value("${hibernate.showSql}")
        private boolean showSql;

        @Bean
        @Primary
        @ConfigurationProperties("c3p0.named-configs.pool")
        @Qualifier("myDataSource")
        public DataSource myDataSource() {
            return new ComboPooledDataSource();
        }

        @Bean
    public PlatformTransactionManager esTransactionManager(@Qualifier("em") EntityManagerFactory em) {
        JpaTransactionManager transactionManager = new JpaTransactionManager(em);
        return transactionManager;
    }

        @Bean
        public LocalContainerEntityManagerFactoryBean em(@Qualifier("myDataSource") DataSource myDataSource, JpaVendorAdapter jpaVendorAdapter) {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(myDataSource);
            entityManagerFactoryBean.setJpaDialect(new HibernateJpaDialect());
            entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
            entityManagerFactoryBean.setPersistenceUnitName("myPersistenceUnit");
            entityManagerFactoryBean.setPackagesToScan("com.company");
            return entityManagerFactoryBean;
        }

        @Bean
        public JpaVendorAdapter jpaVendorAdapter(@Value("${hibernate.dialect}") String hibernateDialect,
                                                 @Value("${hibernate.showSql}") boolean showSql) {
            HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
            jpaVendorAdapter.setDatabasePlatform(hibernateDialect);
            jpaVendorAdapter.setShowSql(showSql);
            return jpaVendorAdapter;
        }
    }

推荐阅读