Spring JPA Repository中的@Transaction行为

时间:2015-06-03 15:46:38

标签: java spring jpa transactions

所以我有一个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注释是否足够用于此?如果不是我该怎么办?

1 个答案:

答案 0 :(得分:1)

根据你的评论,我理解对dumpToFile的调用是完全随机的,它可能发生在你的findAll和deleteAll之间有一个保存。

在进一步讨论之前,我建议阅读一下关于什么是交易以及Spring的交易机制是如何工作的。我将尝试简要概述一下,但现在这已经是详尽无遗的了。事务是您在任何系统上执行的逻辑操作。我说Logical因为一个特定的交易,我可能要更新2条记录(付款和订单跟踪,如果你想想一个例子)。如果其中一个更新由于某种原因失败,则另一个更新也会失败。即使更新了2条记录,整个操作也是原子操作。因此,我们将这两个操作称为一个事务。

还有其他参数[ACID],但单个事务应该是单个逻辑操作。

在您的情况下,您将整个存储库标记为只读。 [有多种类型的事务,只读只允许您读取数据但不能修改它]。所以我不确定你的删除是否会发生。但是,如果您将配置更改为允许删除,那么我们会遇到其他问题。锁定的问题。

只读交易通常(有警告)锁定您正在阅读的表格。如果你想在执行findAll和deleteAll时锁定你的表,你可以将这两个包装在一个事务中,将表标记为已锁定(这将阻止在当前事务完成之前阻止其他查询),你的东西和提交/回滚。提交/回滚释放锁。其他查询继续执行。

这只是一种做法。另一种方法是同步对存储库的访问并以Java方式锁定事务(尽管我不推荐它)。可能还有其他方法,但是出于几个原因,一个好的设计不应该理想地锁定整个表。

这不是为您提供代码,但我的想法是让您了解有关事务,表锁定以及执行此操作的替代设计的更多信息。