在您的示例中,这取决于您的存储库是否有。@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”将确保两种存储库方法 - 并且将参与单个事务,并且 isolation=“Serializable”将确保没有人可以干扰它。它将为涉及 get() & add() 的表保持锁定。findByName()
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);
}
}