考虑以下(伪kotlin)代码:
@Transactional
fun updateDatabase(entity: Entity) {
// do something with entity
}
fun kafkaProduce() {
updateDatabase(entity)
kafka.sendMessage(entity.id)
}
fun kafkaConsume(entityId: Long) {
em.find(Entity::class, entityId)
}
我们的问题是,我们通常使用隔离级别READ UNCOMMITTED
。调用kafkaProduce
时,碰巧在kafkaConsume
中的事务完成之前调用了updateDatabase
并读取了实体的旧状态。有没有办法做某种em.waitForCompletion
以便交易真正完成,然后再将消息发送给Kafka?
答案 0 :(得分:0)
如果它们是不同的交易,那么您可能需要使用悲观锁定:
@Entity()
export class Persona {
@ObjectIdColumn()
private id:ObjectID
@Column()
private nombre:string;
@Column()
private edad:number;
@Column()
private telefono:string;
@Column()
private esCasado:boolean;
//getters and setters
这将在数据库行上创建物理锁。当其他事务尝试查询该事务而第一个事务仍未完成时,它将获得fun updateDatabase(entity: Entity) {
Entity entityMerged = entityManager.merge(entity);
entityManager.lock(entityMerged, LockModeType.PESSIMISTIC_WRITE);
。
然后,您可以抓住它并尝试进行恢复,直到释放锁为止。
请小心,不要过度使用此策略并在投入生产之前对其进行很好的测试。如果交通繁忙,可能会成为瓶颈。
答案 1 :(得分:0)
我通过AlanHay找到了解决方案:
@Transactional
public void a transactionalMethod() {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
public void afterCommit(){
//do stuff right after commit
System.out.println("commit!!!");
}
});
//do db stuff
}