//entities
@Entity
public class ObjectB{
@Id
private long id;
...
}
@Entity
public class ObjectC{
@Id
private long id;
...
}
//servicies
@Service
@Transactional
public class ClassA{
@Autowired
private ClassB classB;
@Autowired
private ClassC classC;
public void methodA(){
classB.insertB(new ObjectB());
classC.insertC(new ObjectC());
}
}
@Service
@Transactional
public class ClassB{
@Autowired
private RepositoryB repositoryB;
public void insertB(ObjectB b){
repositoryB.save(b);
}
}
@Service
@Transactional
public class ClassC{
@Autowired
private RepositoryC repositoryC;
public void insertC(ObjectC c){
repositoryC.save(c);
}
}
//repositories
@Repository
public interface RepositoryB extends CrudRepository<ObjectB, String>{
}
@Repository
public interface RepositoryC extends CrudRepository<ObjectC, String>{
}
我希望ClassA的methodA在methodB或methodC抛出异常后,可以回滚数据库中所有更改。但实际上它并没有这样做,所有的更改都保留了下来。我错过了什么?我应该添加什么才能让它按照我的要求工作?我正在使用Spring Boot 2.0.6!我没有特别配置事务处理! 编辑1 如果有帮助的话,这是我的主类:
@SpringBootApplication
public class JobWebappApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(JobWebappApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(JobWebappApplication.class, args);
}
}
当出现异常时,我在控制台中看到的内容如下:
Completing transaction for [com.example.ClassB.insertB]
Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@31d4fbf4] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@df9d400] bound to thread [http-nio-8080-exec-7]
Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@1d1ad46b] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-8080-exec-7]
Getting transaction for [com.example.ClassC.insertC]
Completing transaction for [com.example.ClassC.insertC] after exception: java.lang.RuntimeException: runtime exception!
Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: runtime exception!
Winning rollback rule is: null
No relevant rollback rule found: applying default rules
Completing transaction for [com.example.ClassA.methodA] after exception: java.lang.RuntimeException: runtime exception!
Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: runtime exception!
Winning rollback rule is: null
No relevant rollback rule found: applying default rules
Clearing transaction synchronization
Removed value [org.springframework.jdbc.datasource.ConnectionHolder@1d1ad46b] for key [HikariDataSource (HikariPool-1)] from thread [http-nio-8080-exec-7]
Removed value [org.springframework.orm.jpa.EntityManagerHolder@31d4fbf4] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@df9d400] from thread [http-nio-8080-exec-7]
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: runtime exception!] with root cause
看起来每次调用方法都会创建一个新的事务!在RuntimeException发生后没有回滚任何东西!
编辑2
这是pom.xml依赖文件:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
这是 application.properties 文件:
spring.datasource.url=jdbc:mysql://localhost:3306/exampleDB?useSSL=false
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.show-sql=true
logging.level.org.springframework.transaction=TRACE
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
spring.datasource.driver.class=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.locationId.new_generator_mappings=false
解决方法
感谢 @M.Deinum,我找到了解决方法!
我使用了错误的数据库引擎(MyISAM),它不支持事务!所以我改变了表格的引擎类型为"InnoDB",它支持事务。我的做法如下:
- 我在application.properties文件中添加了此属性,告诉JPA应该使用哪种引擎类型来“操作”表格:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
- 我删除了数据库中所有现有的表(使用了错误的引擎类型),并让JPA重新创建这些表格,使用正确的引擎类型(InnoDB)。
现在,所有抛出的RuntimeException都会使事务回滚到其中所做的所有更改。
注意:我发现如果抛出的异常不是RuntimeException的子类,则不会应用回滚,已经完成的所有更改仍将保留在数据库中。
@Transactional
是org.springframework.transaction.annotation.Transactional
而不是javax.transaction.Transactional
。 - Ken Chanspring-test
依赖项(该依赖项已包含在spring-boot-starter-test
依赖项中)。您正在使用 MYSQL,请确保您正在使用带有 InnoDB 表而不是 MyISAM 表的 MySQL。后者不支持事务。 - M. Deinum