我目前正在使用JPA和Kafka的项目中。我正在尝试找到一套将这些操作结合起来的良好实践。
在现有代码中,生产者和jpa都在同一笔交易中使用,但是,据我所读,似乎他们并不共享交易。
@PostMapping
@Transactional
public XDto createX(@RequestBody XRequest request) {
Xdto dto = xService.create(request);
kafkaProducer.putToQueue(dto, Type.CREATE);
return dto;
}
其中的kafka生产者定义如下:
public class KafkaProducer {
@Autowired
private KafkaTemplate<String, Type> template;
public void putToQueue(Dto dto, Type eventType) {
template.send("event", new Event(dto, eventType));
}
}
这是结合jpa和kafka的有效用例,事务边界是否正确定义?
答案 0 :(得分:7)
这在事务失败时将无法正常工作。卡夫卡互动不属于交易的一部分。
您可能想看看TransactionalEventListener,您可能想在AFTER_COMMIT事件中将消息写到kafka。即使这样,kafka发布也可能会失败。
另一个选择是在执行操作时使用jpa写入db。让debezium从您的数据库中读取更新的数据,并将其推送到kafka。该事件将采用不同的格式,但内容将更加丰富。
答案 1 :(得分:4)
通过查看您的问题,我假设您正在尝试实现OLTP系统的CDC(更改数据捕获),即将要进行事务处理的每个更改都记录到事务数据库中。有两种方法可以解决此问题。
如果CDC是您的用例,请尝试使用任何可用的解决方案。
答案 2 :(得分:2)
正如其他人所说,您可以使用更改数据捕获来将应用于数据库的更改安全地传播到Apache Kafka。您无法在单个事务中更新数据库和Kafka,因为后者不支持任何类型的两阶段提交协议。
您可以CDC表本身,或者,如果您希望对发送给Kafka的结构有更多控制,请应用“发件箱”模式。在这种情况下,您的应用程序将写入其实际业务表以及包含要发送到Kafka的消息的“发件箱”表。您可以在此blog post中找到有关此方法的详细说明。
免责声明:我是这篇文章的作者,也是Debezium的负责人,Debezium是其他一些答案中提到的CDC解决方案之一。
答案 3 :(得分:0)
您不应将正在发送的消息发送给kafka。如果在无法将事件发送到kafka时需要逻辑,然后还原事务,则在这种情况下最好使用spring-retry
。只需将与发送事件相关的代码放入带有注释的方法@Retryable
中,并添加具有注释的@Recover
方法,并将逻辑恢复到以前所做的更改的逻辑即可。