Я переключил приложение, с которого я работаю, используя плейер времени загрузки AspectJ с использованием прокси-серверов Spring CGlib, и сразу после того, как я сделал это, было много частей кода, в которых я начал получать спящие ленивые загрузки, исключая случаи, когда в прошлом исключений не было.
Я смог разрешить эти ленивые исключения для загрузки, добавив @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
в кучу ранее открытых методов, у которых не было каких-либо транзакционных атрибутов, но называемых репозиториями w760 для чтения данных из базы данных.
Кто-нибудь знает, почему добавление @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
устраняет исключения для лэйзинга загрузки в спящем режиме и почему эти аннотации не требуются при вставке времени AspectJ, но они требуются без?
Обновление 2 Я считаю, что удаление AspectJ не было проблемой, но проблема заключалась в том, что я действительно не понимал реального поведения распространения SUPPORTS. В частности, как SUPPORTS взаимодействовали с JPA EntityManager, и поэтому я удалил кучу распространение SUPPORTS, которое вызвало ленивые ошибки загрузки. Прочитав исходный код для Spring Transaction Manager, все стало ясно, что делать. Основная идея, что документация Spring не очень хорошо указывает на то, что аннотации @Transactional используются в качестве точек синхронизации, которые связывают жизненный цикл EntityManager с началом и окончанием транзакционного метода. Также настоятельно рекомендуем эту серию статей на http://www.ibm.com/developerworks/java/library/j-ts1/ и этот пост в блоге http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/
Обновление 1
Это не относится к вызовам частных методов @Transactional, которые не проходят через прокси-сервер AOP. Эти проблемы происходят с общедоступными методами, вызываемыми из других служб.
Вот пример структуры кода, где я вижу возникшую проблему.
@Service
public class FooService
{
@Autowired
private BarService barService;
public void someMethodThatOnlyReads() {
SomeResult result = this.barService.anotherMethodThatOnlyReads()
// the following line blows up with a HibernateLazyLoadingEcxeption
// unless there is a @Transactional supports annotation on this method
result.getEntity().followSomeRelationship();
}
}
@Service
public class BarService
{
@Autowired
private BarRepository barRepo;
public SomeResult anotherMethodThatOnlyReads()
{
SomeEntity entity = this.barRepo.findSomeEntity(1123);
SomeResult result = new SomeResult();
result.setEntity(entity);
return result;
}
}
@Repository
public class BarRepository
{
@PersistenceContext
private EntityManager em;
public SomeEntity findSomeEntity(id Integer)
{
em.find(SomeEntity.class,id);
}
}