Entity отваливается от управления Spring Data во время транзакции
Имеется обычный бин спринга. В нем некий метод, не отмеченный аннотацией @Transactional, дергает метод приведенный ниже:
@Transactional //spring tx, not javax
public void saveSubCategories(int id, ...) {
Optional<Category> optionalCategory = categoryRepository.findById(id);
//some code
Category category = optionalCategory.get();
List<SubCategory> dbSubCategories = category.getSubCategories();
int size = dbSubCategories.size();
///some code
Любое взаимодействие с dbSubCategories (для примера взял получение размера списка) вызывает LazyInitException.
Jpa entity настроены так:
@Entity
@Table(name = "category")
public class Category {
//fields and getters/setters
@OneToMany(mappedBy = "category", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public List<SubCategory> getSubCategories() { return subCategories; }
public void setSubCategories(List<SubCategory> subCategories) { this.subCategories = subCategories; }
@Entity
@Table(name = "subcategory")
public class SubCategory {
//fields and getters/setters
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "category_id")
public Category getCategory() { return category; }
public void setCategory(Category category) { this.category = category; }
Также пожалуй важно заметить что в бд таблица subcategory пуста, т.е. должно бы просто вернуть size = 0;
Если поставить в Category fetch = EAGER то работает корректно.
В ходе экспериментов также выяснилось что если в том же методе дальше выполнить
SubCategory subCategory = new SubCategory();
subCategory.setCategory(category);
subCategoryRepository.save(subCategory);
То все падает с ошибкой springframework.dao.InvalidDataAccessApiUsageException ... detached entity passed to persist: entity.Category
Как это так? Транзакция ведь не закрыта, все выполняется в одном методе, но объект category отваливается от управления jpa.
И как избежать использования fetch = EAGER? И почему падает LazyInit во время транзакции?
Ответы (1 шт):
А ларчик просто открывается:
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.