【发布时间】:2020-04-12 05:46:52
【问题描述】:
我有 2 个服务:RecentRecordService 和 BookService。
@Service
public class RecentRecordService {
@Transactional
public List<Book> getRecentReadBooks() {
List<Long> recentReadBookIds = getRecentReadBookIds();
List<Book> recentReadBooks = new ArrayList<>();
for (Long bookId : recentReadBookIds) {
try {
Book book = bookService.getBook(bookId);
recentReadBooks.add(book);
} catch (AccessDeniedException e) {
// skip
}
}
return recentReadBooks;
}
}
@Service
public class BookService {
@Transactional
public Book getBook(Long bookId) {
Book book = bookDao.get(bookId);
if (!hasReadPermission(book)) {
throw new AccessDeniedException(); // spring-security exception
}
return book;
}
}
假设getRecentReadBookIds() 返回[1, 2, 3]。
当会话用户拥有从getRecentReadBookIds() 返回的所有图书 ID 的权限时,一切正常。 getRecentReadBooks() 将返回一个包含 3 个 Books 的列表。
突然,第 2 本书的所有者将其权限设置从“公共”更改为“私人”。因此,会话用户不能再阅读本书#2。
我期待getRecentReadBooks() 将返回一个包含 2 个Books 的列表,其中包含第 1 本书和第 3 本书的信息。但是,该方法失败并出现以下异常:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
经过一番研究,我发现它与事务传播有关。即使我使用 try-catch 处理 getRecentReadBooks() 中的 AccessDeniedException,事务也会被标记为“仅回滚”。
这个问题似乎可以通过把getBook()的@Transactional注解改成:
@Transactional(propagation = Propagation.NESTED)
public Book getBook(Long bookId) {
// ...
}
或
@Transactional(noRollbackFor = AccessDeniedException.class)
public Book getBook(Long bookId) {
// ...
}
但是,我想知道是否可以仅通过修改RecentRecordService 来解决问题。毕竟RecentRecordService 是想自己处理AccessDeniedException 的人。
任何建议都会有所帮助。谢谢。
【问题讨论】:
标签: java spring hibernate spring-transactions