【发布时间】:2020-11-10 23:11:19
【问题描述】:
在我开始使用 Spring WebFlux 的 Web 客户端中,出现以下异常:
reactor.core.Exceptions$ErrorCallbackNotImplemented: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
代码:
@Service
@Transactional
@Slf4j
public class PersonSyncServiceImpl
extends HotelApiCommunicationService implements PersonSyncService {
private static final String REST_ENDPOINT_PATH = "/api/sync/person";
@PersistenceContext
private EntityManager em;
@Autowired
private SynchronizationService syncMgr;
@Override
public int initialSyncPersonData(ObiektDTO obiekt) {
WebClient client = WebClient.create("http://" + obiekt.getAdresIp());
AtomicInteger count = new AtomicInteger(0);
Flux<Person> personFlux = client.get()
.uri(REST_ENDPOINT_PATH)
.retrieve()
.bodyToFlux(Person.class);
personFlux.subscribe(person -> {
CNPerson cnPerson = syncMgr.convertObject(person, CNPerson.class);
cnPerson.setObiektLoid(obiekt.getLoid());
em.persist(cnPerson);
count.getAndIncrement();
});
return count.get();
}
}
我知道问题出在这条线上,因为 reactor 无法获取实体管理器。
em.persist(cnPerson);
服务器上的控制器方法:
@GetMapping(value = "/person", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<Person> getPersonList() {
return Flux.fromStream(
personDao.findAll().stream());
}
如何解决?如何使用反应器访问事务并使用 JPA 将记录保存到数据库?
【问题讨论】:
-
您需要调用外部服务上的方法来进行保存,请注意,如果您有 100 个人,那么您也有 100 个人交易!。
-
@M.Deinum 是否可以在一笔交易中完成?
-
不,除非您使用 Spring 5.2 并使用整个反应式堆栈,这不适用于 JPA,因为它使用的是阻塞的 JDBC。因此,如果没有完全反应式堆栈是不可能的。
-
@M.Deinum: 有没有其他方法可以在客户端获取流并将每条记录在一个事务中保存到数据库中而不使用 Webflux?
-
您可以使用 toIterable() 方法,它返回您的人员的 Iterable,但该方法是阻塞的,但是我可以看到您的方法 initialSyncPersonData 返回不正确的计数,因为订阅是异步工作的。
标签: java spring spring-boot spring-webflux entitymanager