我有两个实体和一个服务。没有@Transactional,一切都可以正常工作(回滚除外)。现在,我在服务方法中添加了@Transactional,以使其成为事务并在发生错误时自动回滚。但是现在,所有使用此方法的测试都以javax.persistence.EntityNotFoundException: Unable to find org.kitodo.mediaserver.core.db.entities.Work with id xyz
失败(xyz是我的工作项的ID)。
然后,我尝试将cascade = {CascadeType.PERSIST, CascadeType.MERGE}
添加到ActionData实体的工作字段中。比起以前,我在同一位置上遇到另一个异常:org.h2.jdbc.JdbcSQLException: Concurrent update in table "WORK": another transaction has updated or deleted the same row [90131-196]
出于某种原因,我认为它会尝试同时使用两个过渡。
原因是什么,我该怎么做?
实体
@Entity
public class Work {
private String id;
private String title;
private String path;
private String hostId;
private Instant indexTime;
private Set<Collection> collections;
private String allowedNetwork = "global";
protected Work() {}
public Work(String id, String title) {
this.id = id;
this.title = title;
}
@Id
public String getId() {
return id;
}
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "work_collection",
joinColumns = @JoinColumn(name = "work_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "collection_name", referencedColumnName = "name"))
public Set<Collection> getCollections() {
return collections;
}
// getters/setters
}
@Entity
public class ActionData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ElementCollection
@CollectionTable(name = "action_parameter")
private Map<String, String> parameter = new HashMap<>();
@ManyToOne
@JoinColumn(name = "work_id", referencedColumnName = "id", nullable = false)
private Work work;
private String actionName;
private Instant requestTime;
private Instant startTime;
private Instant endTime;
private ActionData() {}
public ActionData(Work work, String actionName, Map<String, String> parameter) {
this.work = work;
this.parameter = parameter;
this.actionName = actionName;
}
// getters/setters
}
服务方法
@Service
public class ActionService {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public Object performRequested(ActionData actionData) throws Exception {
// some checks
actionData.setStartTime(Instant.now());
// !!! javax.persistence.EntityNotFoundException: Unable to find org.kitodo.mediaserver.core.db.entities.Work with id xyz
actionRepository.save(actionData);
IAction actionInstance = getActionInstance(actionData.getActionName());
Object result;
result = actionInstance.perform(actionData.getWork(), actionData.getParameter());
actionData.setEndTime(Instant.now());
actionRepository.save(actionData);
return result;
}
}
测试
@Test
public void performRequestedAction() throws Exception {
// given
init();
work1 = entityManager.persist(work1);
actionData1 = new ActionData(work1, "mockAction", parameter1);
actionData1.setRequestTime(Instant.now());
actionData1 = entityManager.persist(actionData1);
entityManager.flush();
// when
Object action = actionService.performRequested(actionData1);
// then
assertThat(action).isNotNull();
assertThat(action).isInstanceOf(String.class);
assertThat(action).isEqualTo("performed");
assertThat(actionData1.getStartTime()).isBetween(Instant.now().minusSeconds(2), Instant.now());
assertThat(actionData1.getEndTime()).isBetween(Instant.now().minusSeconds(2), Instant.now());
}
答案 0 :(得分:0)
我怀疑您的单元测试不在自动提交模式下工作。
问题可能是您没有在测试函数中进行插入事务。
因此,调用的方法actionService.performRequested()无法看到保存的数据,该方法启动了一个全新的事务。不允许该事务查看任何脏数据。 因此,可以通过设置自动提交模式或提交将actionData1保留在performRequestedAction中的事务来确保保存了数据。