我需要一些帮助来尝试调试我的Spring启动应用程序的事务管理无法正常工作的原因。
基本的想法是我有两个表,我想写一些东西。当两个表中的一个出现任何问题时,应该回滚事务,不应该写入数据库。
以下是代码的简化版本:
@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);
}
}
}
我执行save方法的类是Spring Data JPA存储库,它们的定义如下:
public interface CalculationRunRepository extends JpaRepository<OffloadedRun, String> {
}
我注释掉的行是必填列。我这样做是为了强制执行ConstraintViolationException来测试在第二个表中保存内容时异常发生的情况。
第一个实体是成功保存的,应该不会发生。我试图找出原因。
我的春季启动应用程序配置了@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注释上显式设置rollbackFor属性,如下所示:
@Transactional(rollbackFor = {Exception.class, MySQLIntegrityConstraintViolationException.class})
但即使这样也不会导致回滚。
编辑:
这些是与JPA / Hibernate相关的弹簧启动设置:
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
答案 0 :(得分:0)
我不确定您为什么在存储库&lt; OffloadedRun,String&gt;中使用String作为您的id类型。您的OffloadedRun域的ID是否为String类型?它应该与OffloadedRun域中的id字段的类型匹配。确保案例。确认, 您能否发布您的OffloadedRun域代码?
答案 1 :(得分:0)
你必须使用org.springframework.orm.hibernate4.HibernateTransactionManager。
您可能正在使用org.springframework.orm.jpa.JpaTransactionManager。