英文:
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
方法。private
和 protected
方法将被忽略。
但是,你现在做的确实不是一个好的实践。对于只读操作(例如从数据库获取数据),你应该使用 @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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论