Spring игнорирует аннотацию @Transactional - PullRequest
0 голосов
/ 13 сентября 2018

в одном из наших проектов мы столкнулись с проблемой, когда Spring игнорировал аннотацию @Transactional, а затем завершился ошибкой со следующей ошибкой.

Ошибка запуска ApplicationContext.Чтобы отобразить отчет об условиях, перезапустите приложение с включенной отладкой.2018-09-13 15: 05: 18,406 ОШИБКА [main] org.springframework.boot.SpringApplication Не удалось запустить приложение org.springframework.dao.InvalidDataAccessApiUsageException: Нет EntityManager с фактической транзакцией, доступной для текущего потока - не может надежно обработать вызов «remove»;вложенным исключением является javax.persistence.TransactionRequiredException: нет EntityManager с фактической транзакцией, доступной для текущего потока - невозможно надежно обработать вызов «remove» в com.my.service.CacheAService.deleteShortTermCache (CacheAService.java:70) ~ [classes /: na]

Я нашел похожие вопросы, но ни одно из решений, примененных к этому случаю.

  • @EnableTransactionManagement присутствует
  • Транзакционный класс реализует интерфейс
  • Транзакционный метод является общедоступным
  • Транзакционный метод не вызывается внутренне

Когда я аннотирую CacheService с помощью @Transactional, все снова работает.Но я пытаюсь понять, почему Spring игнорирует @Transactional на CacheAService.

Я пытался протоколировать перехватчик транзакций Spring, но нет упоминания о CacheA.Это единственное связанное, что регистрируется.

2018-09-13 15: 05: 18,242 TRACE [main] org.springframework.transaction.interceptor.TransactionInterceptor Не нужно создавать транзакцию для[org.springframework.data.jpa.repository.support.SimpleJpaRepository.deleteByValidity]: этот метод не транзакционный.

Вот упрощенный код.Код вызывается во время запуска приложения Spring ContextRefreshedEvent.

@Service
public class CacheService implements Cache {

    @Autowired
    private CacheA cacheAService;
    @Autowired
    private CacheB cacheBService;

    @Override
    public void clearCache() {
        cacheAService.deleteShortTermCache();
        cacheBService.deleteAll();
    }
}

public interface CacheA {
    void deleteShortTermCache();
}

@Service
@Transactional(readOnly = true)
public class CacheAService implements CacheA {

    @Autowired
    private CacheARepository cacheARepository;

    @Override
    @Transactional
    public void deleteShortTermCache() {
        cacheARepository.deleteByValidity(CacheValidity.SHORT_TERM);
    }
}

public interface CacheB {
    void deleteAll();
}

@Service
@Transactional(readOnly = true)
public class CacheBService implements CacheB {

    @Autowired
    private CacheBRepository cacheBRepository;

    @Override
    @Transactional
    public void deleteAll {
        cacheBRepository.deleteAll();
    }
}

public enum CacheValidity {
    SHORT_TERM,
    LONG_TERM
}

@Repository
public interface CacheARepository extends JpaRepository<CacheItem, Integer> {
    void deleteByValidity(CacheValidity validity);
}

public enum CacheItemKey {
    AVAILABLE,
    FUTURE,
    AVAILABLE_UTM,
    FUTURE_UTM,
    REGION
}

@Entity
@Table(name = "cache_item")
public class CacheItem {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cache_item_id_seq")
    @SequenceGenerator(name = "cache_item_id_seq", sequenceName = "cache_item_id_seq", allocationSize = 1)
    private Integer id;

    @Column(nullable = false, unique = true)
    @Enumerated(EnumType.STRING)
    private CacheItemKey key;

    @Column(nullable = false)
    private String value;

    @Column(name = "date_modified", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateModified;

    @Column(nullable = false)
    @Enumerated(EnumType.STRING)
    private CacheValidity validity;

    public Integer getId() {
        return id;
    }

    public void setId(final Integer id) {
        this.id = id;
    }

    public CacheItemKey getKey() {
        return key;
    }

    public void setKey(final CacheItemKey key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(final String value) {
        this.value = value;
    }

    public Date getDateModified() {
        return dateModified;
    }

    public void setDateModified(final Date dateModified) {
        this.dateModified = dateModified;
    }

    public CacheValidity getValidity() {
        return validity;
    }

    public void setValidity(final CacheValidity validity) {
        this.validity = validity;
    }

}

Edit: После некоторого копания я нашел это в журналах.

2018-09-14 06: 24: 11,174 INFO [localhost-startStop-1] org.springframework.context.support.PostProcessorRegistrationDelegate $ BeanPostProcessorChecker Бин 'cacheAService' типа [com.my.service.CacheAService] не подходит для обработки всемиBeanPostProcessors (например: не имеет права на авто-проксирование)

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Мы обнаружили, что эта проблема вызвана автоматической настройкой Spring Boot . Поскольку автоконфигурация уже настраивает управление транзакциями, наша пользовательская конфигурация @EnableTransactionManagement сломала создание экземпляров советников по транзакциям. Удаление @EnableTransactionManagement из нашей конфигурации решает проблему.

0 голосов
/ 13 сентября 2018

Попробуйте использовать только одну Transactional аннотацию (в классе или методе). Возможно, проблема в @Transactional(readOnly = true), потому что ваша транзакция не доступна только для чтения, я не уверен, какую аннотацию Transactional предпочитает Spring. Попробуйте использовать:

@Service
public class CacheAService implements CacheA {

    @Autowired
    private CacheARepository cacheARepository;

    @Override
    @Transactional
    public void deleteShortTermCache() {
        cacheARepository.deleteByValidity(CacheValidity.SHORT_TERM);
    }
}

или

@Service
@Transactional
public class CacheAService implements CacheA {

    @Autowired
    private CacheARepository cacheARepository;

    @Override
    public void deleteShortTermCache() {
        cacheARepository.deleteByValidity(CacheValidity.SHORT_TERM);
    }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...