Сбой проверки метода @Transactional: одновременное обновление в таблице «РАБОТА»: другая транзакция обновила или удалила ту же строку - PullRequest
0 голосов
/ 23 октября 2018

У меня есть две сущности и служба.Без @Transactional все работало нормально (кроме отката).Теперь я добавил @Transactional в метод service, чтобы сделать его транзакцией и автоматически откатывать ошибки.Но теперь все тесты, использующие этот метод, терпят неудачу с javax.persistence.EntityNotFoundException: Unable to find org.kitodo.mediaserver.core.db.entities.Work with id xyz (xyz - это идентификатор моего рабочего элемента).

Затем я попытался добавить 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());
}

1 Ответ

0 голосов
/ 24 октября 2018

Я подозреваю, что ваш Unittest не работает в режиме автоматической фиксации.

Возможно, проблема в том, что вы не фиксируете транзакцию вставки в своей функции тестирования.

Поэтому сохраненныеданные не могут быть просмотрены вызванным методом actionService.performRequested (), который запускает совершенно новую транзакцию.Эта транзакция не сможет увидеть грязные данные.Поэтому либо убедитесь, что данные сохранены, либо установив режим autocommit, либо совершив транзакцию, которая сохраняет actionData1 в executeRequestedAction.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...