java 如何确保@Entity在@Async方法中存在?

wwtsj6pe  于 2023-10-14  发布在  Java
关注(0)|答案(2)|浏览(114)

我想创建一个实体,并在事务中触发一个@Async方法来对同一个实体执行一些更改。更改也应该持久化。
问题:由于我必须在事务中触发@Id方法,我可以使用实体中自动生成的@Id。但是,如果是这样的话,那么这个方法就必须首先通过这个ID来获取实体,而大多数情况下,这个ID还不存在。
只有当我把一些Thread.sleep()作为第一个语句放在Thread.sleep()方法中时,才能确保该实体已被外部事务持久化。
但这种解决方案并不好。问:我如何确保在DB2C方法中,它应该等待实体在DB中存在?

@Service
public class OuterService {
    @Service
    private SyncService service;

    @Transactional
    public void process() {
        service.mySyncMethod();
        //etc
    }
}

@Service
public class SyncService {
    @Transactional
    public void mySnycMethod() {
        Entity entity = new MyEntity();
        //fill entity
        dao.save(entity);
        asyncService.performLongRunningTask(entity.getId());
    }
}

@Service
public class AsycnService {
    @Async
    @Transactional
    public voi performLongRunningTask(Long id) {
        //problem: is mostly == null because this is executed before the outer transaction completes
        //only works if I put like Thread.sleep(5000) in between. but how can I really ensure the entity exists before executing this async lookup?
        MyEntity entity = dao.findOne(id);

        //perform long running task
        //change some fields in entity accordingly
        dao.save(entity);
    }
}
dy2hfwbg

dy2hfwbg1#

您可以使用TransactionSynchronizationManager.registerSynchronization()并实现afterCommit()方法在事务提交时注册一个钩子。

@Transactional
public void mySnycMethod() {
    Entity entity = new MyEntity();
    // fill entity
    dao.save(entity);
    // performLongRunningTask will start after the transaction has been
    // commited
    TransactionSynchronizationManager
            .registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    asyncService.performLongRunningTask(entity.getId());
                }
            });

}

但是请注意Javadoc关于在应用程序中使用TransactionSynchronizationManager的说法:
由资源管理代码使用,但不由典型应用程序代码使用

ffdz8vbo

ffdz8vbo2#

我最终实现的解决方案是通过ApplicationEventApplicationEventPublisher@ApplicationEventListenerphase = AFTER_COMMIT一起使用Spring应用程序事件。然后,在事务和实体持久化之后,将调用您的BRAC方法。

public class MyEvent extends ApplicationEvent {
    private Long entityId;
    
    // constructor and getter
    ...
}

@Service
public class SyncService {
    @Autowired
    ApplicationEventPublisher pub;

    @Transactional
    public void mySyncMethod() {
        Entity entity = new MyEntity();
        //fill entity
        dao.save(entity);
        pub.publishEvent(new MyEvent(entity.getId()));
    }
}

@Service
public class AsyncService {
    @Async
    @Transactional
    @TransactionalEventListener(phase = AFTER_COMMIT)
    public void performLongRunningTask(MyEvent event) {
        MyEntity entity = dao.findOne(event.getEntityId());

        // do stuff
    }
}

相关问题