在您的示例中,这取决于您的存储库是否有@Transactional
。
如果是,那么在您的情况下(按原样)服务-不应该使用@Transactional
(因为没有必要使用它)。如果您计划向处理另一个表/存储库的服务添加更多逻辑,您可以@Transactional
稍后添加 - 那么会有一点。
@Transactional
如果不是 - 那么如果您想确保您没有隔离问题,那么您的服务应该使用,例如您没有阅读尚未通勤的内容。
--
如果谈论一般的存储库(作为 crud 收集接口):
- 我会说:不,你不应该使用@Transactional
为什么不:如果我们认为存储库在业务上下文之外,并且它不应该知道传播或隔离(锁定级别)。它无法猜测它可能涉及到哪个事务上下文。
存储库是“无业务的”(如果您相信的话)
说,你有一个存储库:
class MyRepository
void add(entity) {...}
void findByName(name) {...}
并且有一个业务逻辑,比如 MyService
class MyService() {
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.SERIALIZABLE)
void doIt() {
var entity = myRepository.findByName("some-name");
if(record.field.equal("expected")) {
...
myRepository.add(newEntity)
}
}
}
即在这种情况下:MyService
决定它想要将存储库涉及到什么。
在这种情况下,propagation="Required" 将确保 BOTH 存储库方法 -findByName()
并且add()
将涉及单个事务,并且 isolation="Serializable" 将确保没有人可以干预。它将为涉及 get() 和 add() 的表保持锁定。
但是其他一些服务可能想以不同的方式使用 MyRepository,根本不涉及任何事务,比如它使用findByName()
方法,对任何限制不感兴趣,以读取它现在可以找到的任何内容。
- 我会说是的,如果您将存储库视为始终返回有效实体(无脏读)等的存储库(避免用户错误地使用它)。即您的存储库应该处理隔离问题(并发性和数据一致性),例如:
我们希望(存储库)确保当我们add(newEntity)
首先检查是否存在具有相同名称的实体时,如果是这样 - 插入,全部在一个锁定工作单元中。(与我们在上面的服务级别所做的相同,但我们没有将此责任转移到存储库)
比如说,不能有 2 个具有相同名称的任务“进行中”状态(业务规则)
class TaskRepository
@Transactional(propagation=Propagation.REQUIRED,
isolation=Isolation.SERIALIZABLE)
void add(entity) {
var name = entity.getName()
var found = this.findFirstByName(name);
if(found == null || found.getStatus().equal("in-progress"))
{
.. do insert
}
}
@Transactional
void findFirstByName(name) {...}
2nd 更像是 DDD 风格的存储库。
我想如果出现以下情况,还有更多内容需要介绍:
class Service {
@Transactional(isolation=.., propagation=...) // where .. are different from what is defined in taskRepository()
void doStuff() {
taskRepository.add(task);
}
}