编辑:
也许这种描述太复杂了。我试着简单总结一下我想要的东西:
我只想为整个方法执行一个MySQL事务。就像我在MySQL的方法开头和结尾START TRANSACTION
手动执行COMMIT
一样。如有任何错误,它应该ROLLBACK
并抛出错误。
方法执行期间的所有更改都是持久的,或者没有。
详细信息:
我有一个方法必须更改数据库中的几个相互依赖的对象。 根据数据,创建/删除数据库中的多个对象,这些对象必须一致。 我有适当的代码和测试,它可以工作。
当然,如果在多个线程中使用此方法,或者在方法运行时更改数据库,则一切都会中断。
我需要围绕数据进行单个数据库事务,以便完成所有更改或不执行任何更改。
根据我收集的内容,@ trannsal(org.springframework.transaction.annotation.Transactional)应该这样做,但是一旦我添加了这个,该方法就不再适用了
以下是我的方法的一些伪代码:
@RestController
public class SomeAPI {
private SomeCrudRepository repository;
@Autowired
public SomeAPI(SomeCrudRepository repository) {
Assert.notNull(repository);
this.repository = repository;
}
@RequestMapping(value = "/complicated-change-something", method = RequestMethod.POST)
@Transactional
public Thing changeData(Thing someEntry, SomeJson changes) throws JsonProcessingException {
ThingEntity metadataEntity = repository.getMetadata(someEntry.getEntityID(), someEntry.getSomethingElse());
if (cond1) {
if (cond2) {
//get all db entries that might change
List<ThingEntity> metadataEntries = repository.getThings(someEntry.getEntityID(), something);
ThingEntity entityBefore = metadataEntries.get(0);
ThingEntityKey entityBeforeKey = new ThingEntityKey(entityBefore.getPk());
entityBefore.setChangedData(data);
repository.delete(entityBeforeKey);
entityBefore = repository.save(entityBefore);
}
//set current entry
ThingEntityKey metadataEntityKey = new ThingEntityKey(metadataEntity.getPk());
metadataEntity.setChangedData(data);
repository.delete(metadataEntityKey);
metadataEntity = repository.save(metadataEntity);
}
...
...
return metadataEntity.toThing();
}
}
因此有一些repository.delete()
和repository.save()
来电。
如果没有@Transactional,如果没有并发访问,则DB中的结果是正确的。
使用@Transactional
,repository.delete()
删除的所有条目都已消失,但repository.save()
中没有存储任何内容!
如果删除所有repository.delete()
,则DB中的任何内容都不会更改(可能是因为DB中的主键会发生冲突,这就是我之前删除它们的原因。但是没有抛出错误)
我在这里做错了吗? 在任何情况下,都不会抛出任何错误,只是测试失败。
答案 0 :(得分:0)
这是因为您从数据库中删除了一个条目(使用其密钥),然后尝试保存引用该条目的对象。
当您发现时,您无法编辑对象键的数据。您必须删除数据库中的实体并插入新实体。但删除实体后,不能再使用引用该实体的Java对象。
所以你要做的就是首先创建一个Java对象的副本(例如使用复制构造函数或克隆),然后从数据库中删除该实体并插入新对象。
遗憾的是,如果您重用引用已删除实体的对象,则Spring Boot没有有用的错误消息。
以下是工作代码:
@RestController
public class SomeAPI {
private SomeCrudRepository repository;
@Autowired
public SomeAPI(SomeCrudRepository repository) {
Assert.notNull(repository);
this.repository = repository;
}
@RequestMapping(value = "/complicated-change-something", method = RequestMethod.POST)
@Transactional
public Thing changeData(Thing someEntry, SomeJson changes) throws JsonProcessingException {
ThingEntity metadataEntity = repository.getMetadata(someEntry.getEntityID(), someEntry.getSomethingElse());
if (cond1) {
if (cond2) {
//get all db entries that might change
List<ThingEntity> metadataEntries = repository.getThings(someEntry.getEntityID(), something);
ThingEntity entityBefore = metadataEntries.get(0);
ThingEntity newEntity = new ThingEntity(entityBefore);
newEntity.setChangedData(data);
repository.delete(entityBefore);
entityBefore = repository.save(newEntity);
}
//set current entry
ThingEntity newEntity = new ThingEntity(metadataEntity);
newEntity.setChangedData(data);
repository.delete(metadataEntity);
metadataEntity = repository.save(newEntity);
}
...
...
return metadataEntity.toThing();
}
}
如评论中所述,请从REST控制器中删除逻辑并将其放在单独的类中。