- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我有一个由一组微服务构建的应用程序。一个服务接收数据,通过 Spring JPA 和 Eclipse 链接将其持久化,然后向第二个服务发送警报 (AMQP)。
根据特定条件,第二个服务然后针对持久化数据调用 RESTfull Web 服务以检索保存的信息。
我注意到有时 RESTfull 服务会返回空数据集,即使数据之前已保存。查看持久化服务的代码,使用了 save 而不是 saveandflush,所以我假设数据刷新的速度不够快以供下游服务查询。
@Transactional
里面的
最佳答案
问题的可能预测
我相信这里的问题与save
无关。对比 saveAndFlush
.问题似乎与 Spring 的性质有关 @Transactional
方法,以及在涉及您的数据库和 AMQP 代理的分布式环境中错误使用这些事务,并且可能会增加对 JPA 上下文如何工作的一些基本误解。
在您的解释中,您似乎暗示您在 @Transactional
内开始您的 JPA 事务。方法,并且在事务期间(但在提交之前),您将消息发送到 AMQP 代理。稍后,在队列的另一端,消费者应用程序获取消息并进行 REST 服务调用。此时,您注意到来自发布方的事务性更改尚未提交到数据库,因此对消费者方不可见。
问题似乎是您在 JPA 事务中传播这些 AMQP 消息,然后才将其提交到磁盘。当消费者读取消息并对其进行处理时,您从发布方的交易可能尚未完成。因此,消费者应用程序看不到这些更改。
如果你的 AMPQ 实现是 Rabbit,那么我之前也见过这个问题。当您开始 @Transactional
使用数据库事务管理器的方法,在该方法中,您使用 RabbitTemplate
发送相应的消息。
如果您的 RabbitTemplate
未使用事务 channel (即 channelTransacted=true
),那么您的消息将在数据库事务提交之前传递。我相信通过在您的 RabbitTemplate
中启用交易 channel (默认情况下禁用) ,你解决了部分问题。
<rabbit:template id="rabbitTemplate"
connection-factory="connectionFactory"
channel-transacted="true"/>
当 channel 被交易时,则
RabbitTemplate
“加入”当前的数据库事务(显然是一个 JPA 事务)。一旦您的 JPA 事务提交,它就会运行一些尾声代码,这些代码也会提交您的 Rabbit channel 中的更改,这会强制实际“发送”消息。
@Transactional
的末尾方法(不幸的是,在您已经发送了 AMQP 消息之后的一段时间 - 如果您不使用如上所述的事务处理 channel )。
@Transactional
方法已在您的发布者应用程序中完成。
save(entity),
EntityManager
不需要立即同步任何更改。大多数 JPA 实现只是将实体标记为内存中的脏,并等到最后一分钟将所有更改与数据库同步并在数据库级别提交这些更改。
EntityManager
决定这样做。当数据库表中有一个触发器需要它运行以生成一些您稍后在事务期间需要的附加记录时,就会发生这种情况的一个经典示例。因此,您强制将更改刷新到磁盘,从而强制运行触发器。
<bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="rabbitTransactionManager" class="org.springframework.amqp.rabbit.transaction.RabbitTransactionManager">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
<bean id="chainedTransactionManager" class="org.springframework.data.transaction.ChainedTransactionManager">
<constructor-arg name="transactionManagers">
<array>
<ref bean="rabbitTransactionManager"/>
<ref bean="jdbcTransactionManager"/>
</array>
</constructor-arg>
</bean>
然后,在您的代码中,您只需使用该链式事务管理器来协调您的数据库事务部分和 Rabbit 事务部分。
@Retry
@Transactional("chainedTransactionManager")
public void myServiceOperation() {
if(workNotDone()) {
doDatabaseTransactionWork();
}
sendMessagesToRabbit();
}
通过这种方式,如果您的 Rabbit 事务部分由于任何原因失败,并且您被迫重试整个链式事务,您将避免重复数据库副作用,只需确保将失败的消息发送给 Rabbit。
关于java - Spring JPA : What is the cost of saveandflush vs save?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43883786/
我想问一下CrudRepository中save()的性能。首先是一个代码示例。 for(int i=0; i childExamples = new ArrayList<>(); Child
我在 Spring Rest 应用程序中使用 Spring data JPA、hibernate、sqlserver。 i) 对于第一个请求,一条记录被插入到数据库中。直到这里工作正常。 ii)当我用
我希望有人遇到过这个问题: 在服务层中,我捕获了一个异常,在 catch block 中,我想在数据库中保存一条记录,调用 saveAndFlush 然后抛出应用程序异常。问题是保存和刷新不会保留记录
我有以下实现。 @Transactional public void saveAndGenerateResult(Data data) { saveDataInTableA(data.some
我使用 Spring Data 和 Hibernate 作为 JPA 实现。 有时我会装载一辆车,操纵它并保存它。使用 Spring JPA-Repository 的代码如下所示: @Entity @
我正在使用 spring-data-jpa interface CrudRepository 在每日批量导入时将大型数据集保存在数据库中。 @Bean public ItemWriter jpaIte
我第一次尝试使用服务/存储库方法,但遇到了一个问题。本质上,我想在我的服务中做的是持久化我的实体,然后在相同的服务方法中使用它的 ID。 最初我打算使用 @GeneratedValue 和 Seque
我在我的bean上使用@OrderBy子句,当我从持久层获取这个对象时,它工作得很好,但是当我尝试使用保存这个数据时 persistedObject = saveAndFlush(MyCustomOb
我有一个由一组微服务构建的应用程序。一个服务接收数据,通过 Spring JPA 和 Eclipse 链接将其持久化,然后向第二个服务发送警报 (AMQP)。 根据特定条件,第二个服务然后针对持久化数
我有一个复杂的实体: public class Task { @OneToOne(orphanRemoval=true, mappedBy="parent") @Cascade(value
我是一名优秀的程序员,十分优秀!