Spring忽略@Transactional注释

时间:2018-09-13 13:48:48

标签: java spring hibernate spring-boot spring-data-jpa

在我们的一个项目中,我们遇到了一个问题,即Spring忽略了@Transactional批注,然后由于以下错误而失败。

  

启动ApplicationContext时出错。显示条件报告   在启用“调试”的情况下重新运行您的应用程序。 2018-09-13 15:05:18,406   错误[main] org.springframework.boot.SpringApplication应用程序   运行失败的org.springframework.dao.InvalidDataAccessApiUsageException:   没有可用于当前线程的实际事务的EntityManager   -无法可靠地处理“删除”呼叫;嵌套异常为javax.persistence.TransactionRequiredException:否EntityManager with   当前线程可用的实际事务-无法可靠地   在处处理“删除”呼叫   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;
    }

}

编辑: 经过一番挖掘,我在日志中找到了这个。

  

2018-09-14 06:24:11,174 INFO [localhost-startStop-1]   org.springframework.context.support.PostProcessorRegistrationDelegate $ BeanPostProcessorChecker   类型[com.my.service.CacheAService]的Bean'cacheAService'不是   有资格被所有BeanPostProcessor处理(例如:   不符合自动代理的条件

2 个答案:

答案 0 :(得分:2)

我们发现此问题是由Spring Boot的自动配置引起的。由于自动配置已经设置了事务管理,因此我们的@EnableTransactionManagement的自定义配置破坏了事务顾问的实例化。从我们的配置中删除@EnableTransactionManagement可以解决此问题。

答案 1 :(得分:1)

尝试仅使用一个Transactional注释(在类或方法中)。可能是@Transactional(readOnly = true)的问题所在,因为您的交易不是只读的,所以我不确定Spring首选哪种Transactional注释。尝试使用:

@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);
    }
} 
相关问题