在您的示例中,这取决于您的存储库是否有 @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" 将确保两个存储库方法 -findByName() 和 add() 都将参与单个事务,并且isolation="Serializable" 将确保没有人可以干预它。它将为涉及 get() 和 add() 的表保持锁定。
但是其他一些服务可能想以不同的方式使用 MyRepository,根本不涉及任何事务,比如它使用 findByName() 方法,对读取任何它现在可以找到的任何内容不感兴趣。
- 我会说是的,如果您将存储库视为始终返回有效实体(无脏读)等的存储库(避免用户错误地使用它)。 IE。您的存储库应处理隔离问题(并发性和数据一致性),例如:
我们希望(存储库)确保当我们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);
}
}