我有一组@Service
bean,它们从一个抽象类继承核心功能。我用@Service
和@Transactional
标记了每个具体的子类服务。抽象超类包含每个服务的公共入口点方法。换句话说,我有类似于以下内容:
abstract class AbstractService {
public void process() {
// Do common initialisation code here
processSpecific();
// Do common completion code here
}
abstract protected void processSpecific();
}
@Service @Transactional
public class FirstSpecificService extends AbstractService {
protected void processSpecific() {
// Do specific processing code here
}
}
@Service @Transactional
public class SecondSpecificService extends AbstractService {
protected void processSpecific() {
// Do different specific processing code here
}
}
每个具体子类服务中的特定代码对DAO层进行多次调用,以对数据库进行更改,其中REQUIRED
为事务传播类型。
现在使用上面定义的服务,我发现在这些具体的子类服务的任何代码中都没有当前事务,并且每次调用DAO层都是创建一个新事务,进行更改,提交交易和返回。
但是,如果我使用@Transactional
注释抽象超类,则正确创建事务 ,并且对DAO层的子调用都参与当前事务。
所以我的问题是,继承@Transactional
行为的规则是什么?为什么Spring不在实际实例化的具体子类服务上使用@Transactional
?在这种情况下,@Transactional
是否需要在超类上,因为这是公共入口点方法的位置?
答案 0 :(得分:12)
从spring transaction文档中,
注意:在代理模式(默认情况下)中,只有“外部”方法 通过代理进入的电话将被截获。这意味着 '自调用',即目标对象中调用某些方法的方法 目标对象的其他方法,不会导致实际的事务 在运行时,即使调用的方法标有@Transactional!
即使您在具体实现上有@Transactional并且您正在通过注释调用实际上是事务性的进程方法,但是由于此内部调用,在子类上调用processSpecific的进程方法不是事务性的。
看看Weaving。
答案 1 :(得分:1)
您是否阅读了有关transaction propagation的部分以及如何使用@Transactional进行配置?
另一个值得关注的领域是Spring建议你annotate concrete classes(反对注释接口)。
答案 2 :(得分:0)
这是一个老问题。但是我遇到了类似的情况,在当前的javadoc中找到了@Transactional注解的解释:
<块引用>在类级别,此注释默认适用于所有 声明类及其子类的方法。请注意,它确实 不适用于在类层次结构中向上的祖先类;方法需要 在本地重新声明以参与子类级别 注释。
因此,当使用继承和类级别注释时,如果超类包含任何应该是事务性的公共方法或调用需要事务性的子类实现的方法,则您应该注释超类而不是子类。
从超类中的方法调用子类实现和注释@Transactional 的方法,而没有超类或该方法被注释@Transactional 是一个错误。 如果两者都被注解,但注解上的属性不一致,也是一个bug。
在一个好的设计中,由子类实现的超类中的虚方法应该只被超类使用,因为它们应该始终具有范围保护,并且子类中永远不需要任何@Transactional注解