hibernate @事务注解未按预期工作

5jvtdoz2  于 2023-03-30  发布在  其他
关注(0)|答案(3)|浏览(117)

我需要一些帮助来调试为什么我的Sping Boot 应用程序的事务管理不起作用。
基本的想法是,我有两个表,我想写的东西。当任何错误发生在这两个表之一,事务应该回滚,什么都不应该写入数据库。
下面是代码的简化版本:

@Transactional
public void archiveTask(String taskId) {

    OffloadedRun run = new OffloadedRun();
    run.setStartDateTime(LocalDateTime.now());
    calculationRunRepository.save(run);

    List<SingleContractCalculationResults> activeResults = contractCalculationResultAccessService.get(taskId);

    for (SingleContractCalculationResults result : example) {
        for (Map.Entry<String, ContractResults> entry : result.getResultsPerScenario().entrySet()) {
            String scenario = entry.getKey();
            ContractResults results = entry.getValue();

            OffloadedCalculationResult offloadedCalculationResult = new OffloadedCalculationResult();

//                offloadedCalculationResult.setOffloadedRun(run);
            offloadedCalculationResult.setContractId(result.getContractId());
            calculationResultRepository.save(offloadedCalculationResult);
        }
    }
}

我执行保存方法的类是Spring Data JPA存储库,其定义如下:

public interface CalculationRunRepository extends JpaRepository<OffloadedRun, String> {
}

我注解掉的那一行是一个强制列。2我这样做是为了强制一个ConstraintViolationException来测试在第二个表中保存某些内容时发生了什么异常。
发生的事情是第一个实体被成功保存,这不应该发生。我试图弄清楚为什么会这样。
我的spring Boot 应用程序配置了@EnableTransactionManagement,以便在我自己的服务中启用@Transactional注解(如此)。
我将org.springframework.transaction.interceptor的日志记录级别更改为TRACE,以查看发生了什么:

o.s.t.i.TransactionInterceptor           : Getting transaction for [be.sodemo.calculator.offloading.TaskArchiverImpl.archiveTask]
o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor           : Completing transaction for [be.sodemo.calculator.offloading.TaskArchiverImpl.archiveTask]

o.h.e.j.s.SqlExceptionHelper             : SQL Error: 1048, SQLState: 23000
o.h.e.j.s.SqlExceptionHelper             : Column 'run_id' cannot be null
o.h.e.j.b.i.AbstractBatchImpl            : HHH000010: On release of batch it still contained JDBC statements
o.a.c.c.C.[.[.[.[dispatcherServlet]      : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'run_id' cannot be null
    at sun.reflect.GeneratedConstructorAccessor2599.newInstance(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java) ~[?:1.8.0_102]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[?:1.8.0_102]
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.40.jar:5.1.40]

在这之后
我不确定如果事务管理正常工作,日志记录会是什么样子,但它看起来像是在完成每个事务。
有没有人知道我下一步可以尝试什么,看看出了什么问题?
编辑:到目前为止,我一直在使用MySQL数据库。我注意到,当我在H2数据库上测试这段完全相同的代码时,回滚似乎按预期工作。我看到的唯一区别是,它抛出了另一个特定于供应商的异常。
我尝试在@Transactional annotation上显式设置rollbackFor属性,如下所示:
@Transactional(rollbackFor = {Exception.class, MySQLIntegrityConstraintViolationException.class})
但即便如此,也没有造成回滚。
编辑:
以下是我的与JPA/Hibernate相关的Spring Boot 设置:

spring:
  jpa:
    hibernate:
      ddl-auto: none
      dialect: org.hibernate.dialect.MySQL5Dialect
    database: mysql
    properties:
      hibernate:
        order_inserts: true
        jdbc:
          batch_size: 50
  datasource:
    url: jdbc:mysql://localhost/local-test-db
    driver-class-name: com.mysql.jdbc.Driver
vfwfrxfs

vfwfrxfs1#

请确认您的应用中使用的是单个dataSource还是多个dataSource。
如果您使用的是单个数据源,则**@Transactional**默认会选择该单个数据源,否则它会从多个数据源中选择任何一个,并且会发生这种类型的无法跟踪的问题。
请查看不同数据源的@Transaction注解
我已使用以下命令解决了此问题

/* This code is present in @Configuration class */
@Bean(name = "postgresDataSource")
DataSource postgresDataSource(){
    // DataSource configuration code
}

@Bean(name = "postgresTransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("postgresDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

/* This code is present in @Service class */
@Override
@Transactional("postgresTransactionManager")
public void save(Map queueMsg) {
    // Transaction specific code 
}
qacovj5a

qacovj5a2#

我不知道为什么你在仓库〈OffloadedRun,String〉中使用String作为id类型。你的OffloadedRun域的id类型为String类型?它应该与你在OffloadedRun域中的id字段的类型匹配。请确保这种情况。为了确认,你能发布你的OffloadedRun域代码吗?

u91tlkcl

u91tlkcl3#

您必须使用org.springframework.orm.hibernate4.HibernateTransactionManager。
您可能正在使用org.springframework.orm.jpa.JpaTransactionManager。

相关问题