阅读了很多SO资料并搜索了所有可能的途径后,我求助于您:
我在@service类中有一个公共方法,该方法通过@repository提交一些事务。尽管我声明事务将在Exception时回滚(并尝试覆盖更通用的类,例如Runtime Exception,Throwable等),但它不会回滚,即使在抛出上述异常后仍会在数据库中提交。在日志级别上记录事务后,这些是我得到的行:
Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.updateCategoryOrder]
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@66a50c93] for key [public abstract void com.aliza.davening.repositories.CategoryRepository.updateCategoryOrder(int,long)] from thread [main]
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [com.aliza.davening.services.AdminService.changeCategoryOrder] after exception: exceptions.ReorderCategoriesException: Now everything should stay the same.
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] o.s.t.i.RuleBasedTransactionAttribute : Applying rules to determine whether transaction should rollback on exceptions.ReorderCategoriesException: Now everything should stay the same.
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] o.s.t.i.RuleBasedTransactionAttribute :
**Winning rollback rule is: RollbackRuleAttribute with pattern [exceptions.ReorderCategoriesException]**
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder@6442cf3e] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@7e1fb22c] from thread [main]
2020-01-01 14:22:40.795 TRACE 1580 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder@7b4c793b] for key [HikariDataSource (HikariPool-1)] from thread [main]
Exception in thread "main" exceptions.ReorderCategoriesException: Now everything should stay the same.
[从日志中看来,他确实研究了回滚的选项,并且只是停留在评估我提供的规则是否足够。我大胆的“制胜法则”是否意味着他得出结论要退后?如果是这样,为什么要进行交易?
或者,如果“获胜规则”意味着他得出的结论是我提供的规则不足以回滚,那么如何使此回滚规则起作用?
这里是代码:
@Service("adminService")
@EnableTransactionManagement
@Transactional(rollbackFor = ReorderCategoriesException.class)
public class AdminService {
public void changeCategoryOrder()
throws ReorderCategoriesException {
//updateCategoryOrder accepts the order and id of a category
categoryRepository.updateCategoryOrder(1, 4);
categoryRepository.updateCategoryOrder(2,11);
categoryRepository.updateCategoryOrder(3, 9);
//this exception should in theory cause the previous commits to rollback, I would think?
throw new ReorderCategoriesException("Now everything should stay the same.");
}
}
这里是执行数据库操作的存储库类:
@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {
@Modifying
@Transactional
@Query("update Category set catOrder=?1 where id=?2")
public void updateCategoryOrder(int newOrder, long categoryId);
}
异常的定义如下:(我尝试从Exception和RuntimeException继承,结果相同)
package exceptions;
@SuppressWarnings("serial")
public class ReorderCategoriesException extends RuntimeException {
public ReorderCategoriesException(String msg) {
super(msg);
}
}
最后,这就是我从主要位置调用方法的方式:
@SpringBootApplication
@EnableAutoConfiguration
@EnableTransactionManagement
public class MyApplication {
public static void main(String[] args) throws ReorderCategoriesException {
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
AdminService adminService = context.getBean(AdminService.class);
adminService.changeCategoryOrder();
}
任何帮助或见解,都会引发异常时回滚数据库操作。
每个categoryRepository.updateCategoryOrder()均在自己的事务上运行。它在每次更新调用后提交,因此数据得以保留。
更新CategoryRepository @Transactional批注以使用当前事务(在AdminService中启动的事务)
@Transactional(propagation = Propagation.REQUIRED )
@Query("update Category set catOrder=?1 where id=?2")
public void updateCategoryOrder(int newOrder, long categoryId);
此更改应在一个事务下运行所有更新(该更新在AdminService中启动,并且应在最后的ReorderCategoriesException上回滚。
事务性Propogation的API参考