未为@Modifying方法调用的@RepositoryEventHandler方法

时间:2018-08-25 19:11:26

标签: spring hibernate spring-mvc transactions spring-data-rest

我有一个如下的事件处理程序类:

@Component
@RepositoryEventHandler(DonationOffer.class)
public class DonationOfferEventHandler {

    @Autowired
    DonationOfferNotificationService notificationService;

    @HandleAfterSave
    public void handleAfterSave(DonationOffer donationOffer){

        Integer donationOfferId = donationOffer.getDonationOfferId();
        System.out.println("updating donation offer");

        switch (donationOffer.getOfferStatus()){
            case Accepted:
                notificationService.generateAcceptedNotification(donationOfferId);
                break;
            case Rejected:
                notificationService.generateRejectedNotification(donationOfferId);
                break;
            case Cancelled:
                notificationService.generateCancelledNotification(donationOfferId);
                break;
        }
    }
}

春季回购如下:

@Transactional
public interface DonationOfferRepo extends PagingAndSortingRepository<DonationOffer,Integer>{

    @Modifying
    @Query(
            "update DonationOffer d " +
                    "set offerStatus = :offerStatus " +
                    "where d.donationOfferId = :donationOfferId"
    )
    @RestResource(path="updateStatus")
    int updateStatus(
            @Param("donationOfferId") Integer donationOfferId,
            @Param("offerStatus") OfferStatus offerStatus
    );
}

问题处理程序是在PUT请求的情况下被调用的,原因是当我调用updateStatus()时,即未调用@HandleAfterSave方法,

a get request to /api/donationOffers/search/updateStatus?donationOfferId=45&offerStatus=Cancelled

如果我缺少某些东西,可以帮忙吗?或者它是默认行为,即仅通过PUT请求才调用@HandleAfterSave吗?

更新: 我创建了一种使用repo save方法测试事件处理程序的方法,如下所示。在这种情况下也不会调用事件处理程序。

@GetMapping(value="/savetest")
    @Transactional
    public ResponseEntity saveTesT(){
        DonationOffer donationOffer = donationOfferRepo.findOne(1);

        donationOffer.setOfferedBottles(donationOffer.getOfferedBottles()+1);

        donationOfferRepo.save(donationOffer);

        return new ResponseEntity(new StringWrapper("OK"), HttpStatus.OK);

    }

1 个答案:

答案 0 :(得分:2)

为了从HandleBeforeSave触发事件,您需要执行PUT请求。如果您正在执行POST请求,则正确的事件处理程序将为HandleBeforeCreate。

UPDATE:我猜测监听器方法没有被调用,原因与查询不调用JPA prePersist,postPersist,preUpdate ...等事件的原因相同。查询对EntityManager.persis更新有不同的执行途径。实体管理器基于身份进行工作,因此可以保证实体实际上已被更新。使用查询时无法得知相同的内容。通常,实体管理器将执行一个查询以获取实体,然后对其进行分析以进行更改,然后将进行UPDATE,或者在不进行更改的情况下将不进行UPDATE。没有机制可以确定执行查询时是否确实发生了更新。

根据文档@Modifying注释,不能保证实际上会进行修改。它保证在调用方法后将清除该会话。这背后的原因再次是查询的执行路径与普通的persist,merge方法不同,并且您不能保证会话将保持完整性。因此,@ Modifying将确保已清除它。