我想在Rest端点上保存一个实体,并立即返回DTO。在那之后,我想添加一些需要一些时间的数据到实体中并保存它。
这就是我的问题真正归结为,在Sping Boot 项目中有没有一种首选的方法来做到这一点?
仅供参考,我想出了两种方法,这两种方法都没有完全发挥作用:
方式1 -异步
@Service
public class EntityServiceImpl implements EntityService {
@Override
@Transactional
public Entity save(Entity entity) {
Entity saved = repository.save(entity);
asyncCalculation(entity.getId());
return saved;
}
@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void asyncCalculation(Long id) {
Entity entity = repository.findById(id).orElseThrow( () ... );
entity.setData(longCalculation(entity));
repository.save(entity);
}
}
我在我的一个@Configuration
类上有@EnableAsync
,并且在所述配置类中还有一个Bean:
@Configuration
@ComponentScan
@EnableAsync
@EnableJpaRepositories(basePackages = "org.repository")
@EnableTransactionManagement
public class SpringConfiguration{
@Bean
public ThreadPoolTaskExecutor asyncExecutor() {
// setting a breakpoint here gets this called, so this should mean the configuration
// gets triggered?
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize();
return executor;
}
然而,这并不运行pklc,它只是顺序运行。是否缺少某些配置?另外,我不太确定这里的transactions,因为save()方法中的commit直到返回之后才出现,所以我不完全理解为什么这会起作用,因为我会在实体真正保存到数据库之前访问它。
方法2 -线程和自己的事务管理
与之前相同的服务类,只是:
@Autowired
private PlatformTransactionManager transactionManager;
@Override
// no transactional
public Entity save(Entity entity) {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
Entity savedEntity = transactionTemplate.execute(status -> {
return repository.save(entity)
});
// now it is commited
new Thread(() -> {
asyncCalculation(savedEntity.getId());
}).start();
return savedEntity ;
}
// no @Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void asyncCalculation(Long id) {
Entity entity = repository.findById(id).orElseThrow( () ... );
entity.setData(longCalculation(entity));
// longCalculation triggers LazyInitializations
repository.save(entity);
}
longCalculation()
触发实体的初始化,但是尽管我用@Transactional(propagation = Propagation.REQUIRES_NEW)
注解了这个方法,我还是得到了一个LazyInitializationException
:无法初始化代理[org.project.domain.SubEntity#767204] -无会话。SubEntity
通过@ManyToOne(fetch = FetchType.LAZY)
连接到Entity
1条答案
按热度按时间carvr3hs1#
基于代理的AOP(这是Spring的默认设置,用于
@Async
和@Transactional
)不能处理内部方法调用。仅仅是因为你在物体内部。你可以用几种方法来解决这个问题:
1.将此方法移动到另一个类并调用它
1.通过进行自调用,这意味着将服务的示例注入到自身中并调用其上的方法(导致外部调用)。
1.对于这种特殊情况:创建一个监听事件的
@TransactionalEventListener
,并将其绑定到AFTER_COMMIT
阶段(数据以这种方式呈现)。