Spring @Transactional继承行为

huangapple go评论59阅读模式
英文:

Spring @Transactional inheritance behavior

问题

I have the following structure:

    @Transactional
    public abstract class BaseServiceImpl<E, K extends Serializable, R extends BaseRepository<E, K>> implements BaseService<E, K> {
    
        protected BaseServiceImpl(R repository) {
            this.repository = repository;
        }
    
        @Override
        public E save(E entity) {
            return repository.save(entity);
        }
    
        @Override
        public List<E> saveAll(List<E> entities) {
            return repository.saveAll(entities);
        }
    
        @Override
        public Optional<E> findByKey(K entityKey) {
            if (entityKey != null) {
                return repository.findById(entityKey);
            }
            return Optional.empty();
        }
    
        @Override
        public List<E> search(String filter, Integer page, Integer limit, String orderBy) {
            return repository.findAll(filter, page, limit, orderBy);
        }
    
        @Override
        public E update(E entity) {
            return repository.save(entity);
        }
    
        @Override
        public void deleteAll() {
            repository.deleteAll();
        }
    
        @Override
        public void delete(E entity) {
            repository.delete(entity);
        }
    
        @Override
        public void deleteByKey(K entityKey) {
            repository.deleteById(entityKey);
        }
    
        @Override
        public Long count() {
            return repository.count();
        }
    }


    @Service
    public class CustomerService extends BaseServiceImpl<CustomerEntity, String, CustomerRepository> {
    
        public CustomerService(CustomerRepository repository) {
            super(repository);
        }
    }

问题是:CustomerService的所有方法会继承 @Transactional 并在事务上下文中执行吗?
另外,我知道Spring文档建议在特定类或方法上使用 @Transactional,但我对如何在类层次结构中避免代码重复使用 @Transactional 感兴趣。

英文:

I have the following structure:

@Transactional
public abstract class BaseServiceImpl<E, K extends Serializable, R extends BaseRepository<E, K>> implements BaseService<E, K> {
protected BaseServiceImpl(R repository) {
this.repository = repository;
}
@Override
public E save(E entity) {
return repository.save(entity);
}
@Override
public List<E> saveAll(List<E> entities) {
return repository.saveAll(entities);
}
@Override
public Optional<E> findByKey(K entityKey) {
if (entityKey != null) {
return repository.findById(entityKey);
}
return Optional.empty();
}
@Override
public List<E> search(String filter, Integer page, Integer limit, String orderBy) {
return repository.findAll(filter, page, limit, orderBy);
}
@Override
public E update(E entity) {
return repository.save(entity);
}
@Override
public void deleteAll() {
repository.deleteAll();
}
@Override
public void delete(E entity) {
repository.delete(entity);
}
@Override
public void deleteByKey(K entityKey) {
repository.deleteById(entityKey);
}
@Override
public Long count() {
return repository.count();
}
}
@Service
public class CustomerService extends BaseServiceImpl<CustomerEntity, String, CustomerRepository> {
public CustomerService(CustomerRepository repository) {
super(repository);
}
}

The question is: will all the methods of CustomerService inherit @Transactional and behave inside transactional context?
Also I know that Spring doc recommends to put @Transactional on specific classes or methods, but I'm interested in the best way to avoid code duplication using @Transactional within class hierarchy.

答案1

得分: 2

@Transactional 注解本身带有 @Inherited 注解,这意味着如果您将其放在基类上,比如您的示例中的 BaseServiceImpl,它将传播到子类,比如您的 CustomerService。https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html

它将表现得就像您直接注解了 CustomerService 一样。

正如您自己注意到的,建议将 @Transactional 放在更细粒度的级别上,比如方法。

请考虑,随着项目的发展,您可能不希望在每个方法上都有 @Transactional 注解,而在早期对基类进行注解的决定可能需要未来的更改。

此外,请考虑到,对于未来的维护人员来说,使用 @Transactional 可能不太可见,因为它将隐藏在基类的背后。

综合考虑利弊,选择对您最合适的方式。

英文:

@Transactional annotation itself is annotated with the @Inherited annotation, which means that if you put it on a base class, such as BaseServiceImpl in your example, it will be propagated to the subclasses, CustomerService for you. https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html

It will behave exactly as if you annotated CustomerService directly.

As you noticed yourself, it is adviced to put @Transactional on a more granular level, such as methods.

Take into consideration that as your project evolves, you may not want the @Transactional annotations on every method and decision to annotate the base class early on may require future changes.

Also, take into consideration that it may be more difficult to maintain as usage of @Transactional may not be as visible for future maintainers as it will be kind of hidden behind the base class.

Take the pros a cons into consideration and choose whatever is most suitable for you.

答案2

得分: 1

@Transactional 在类级别上将应用于每个 public 方法。privateprotected 方法将被忽略。

但是,你现在做的确实不是一个好的实践。对于只读操作(例如从数据库获取数据),你应该使用 @Transactional(readonly = true),因为它与仅 @Transactional 相比有优化。

因此,我建议不要担心重复,只需将注解放在你需要的地方。

额外提示:请注意,从同一Bean内的另一个 @Transactional 方法调用带有 @Transactional(propagation = Propagation.REQUIRES_NEW) 注解的方法不会创建新的事务,这是由于Spring代理行为导致的。

英文:

@Transactional on a class level will be applied to every public method. private and protected methods will be ignored.

But what you are doing is really not good practice. For read-only operation (e.g getting from the database), you should use @Transactional(readonly = true) because it has optimizations compared to only @Transactional.

Therefore, I suggest not worrying about duplications and just put the annotation where you need it.

Extra: Be aware that calling method annotated with @Transactional(propagation = Propagation.REQUIRES_NEW) from another @Transactional method within the same bean will not create new transaction due to Spring proxy behavior.

huangapple
  • 本文由 发表于 2023年7月6日 18:18:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76627796.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定