所以我有一个Spring JPA存储库:
@Transactional(readOnly = true)
public interface UsageReportsRepository extends JpaRepository<UsageReports, Long> {
@Query(value = "select u from UsageReports u where u.username=:username AND u.requestType='USER_ACTIVITY' ORDER BY u.activityEndTime DESC")
public List<UsageReports> getLastActiveTime(@Param("username") String username, Pageable pageable);
}
使用此存储库的两个过滤器。
public class UsageReportingInterceptor implements HandlerInterceptor {
@Autowired
private UsageReportsRepository usageReportsRepository;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Do stuff
usageReportsRepository.save(usageReportsBean)
}
}
public class DumpToFile {
@Autowired
private UsageReportsRepository usageReportsRepository;
@Override
public boolean dumpToFile() throws Exception {
// Do stuff
List<UsageReports> usageReports = usageReportsRepository.findAll()
usageReportsRepository.deleteAll()
// Write to file
}
}
我觉得不需要服务层,因此我直接从我的过滤器中调用它们。一个过滤器使用此存储库插入数据,另一个过滤器清除数据并将其放入文件中。两者都是独立的,可以以任意顺序执行。我想确保我不会在此过程中丢失任何数据。 @Transactional注释是否足够用于此?如果不是我该怎么办?
答案 0 :(得分:1)
根据你的评论,我理解对dumpToFile的调用是完全随机的,它可能发生在你的findAll和deleteAll之间有一个保存。
在进一步讨论之前,我建议阅读一下关于什么是交易以及Spring的交易机制是如何工作的。我将尝试简要概述一下,但现在这已经是详尽无遗的了。事务是您在任何系统上执行的逻辑操作。我说Logical因为一个特定的交易,我可能要更新2条记录(付款和订单跟踪,如果你想想一个例子)。如果其中一个更新由于某种原因失败,则另一个更新也会失败。即使更新了2条记录,整个操作也是原子操作。因此,我们将这两个操作称为一个事务。
还有其他参数[ACID],但单个事务应该是单个逻辑操作。
在您的情况下,您将整个存储库标记为只读。 [有多种类型的事务,只读只允许您读取数据但不能修改它]。所以我不确定你的删除是否会发生。但是,如果您将配置更改为允许删除,那么我们会遇到其他问题。锁定的问题。
只读交易通常(有警告)锁定您正在阅读的表格。如果你想在执行findAll和deleteAll时锁定你的表,你可以将这两个包装在一个事务中,将表标记为已锁定(这将阻止在当前事务完成之前阻止其他查询),你的东西和提交/回滚。提交/回滚释放锁。其他查询继续执行。
这只是一种做法。另一种方法是同步对存储库的访问并以Java方式锁定事务(尽管我不推荐它)。可能还有其他方法,但是出于几个原因,一个好的设计不应该理想地锁定整个表。
这不是为您提供代码,但我的想法是让您了解有关事务,表锁定以及执行此操作的替代设计的更多信息。