ObjectOptimisticLockingFailureException при запуске тестаJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 ObjectOptimisticLockingFailureException при запуске теста

Сообщение Anonymous »

При выполнении теста org.springframework.orm.ObjectOptimisticLockingFailureException возникает следующая ошибка: строка была обновлена ​​или удалена другой транзакцией (или сопоставление несохраненных значений было неверным): [com.study.cardStudy.entity.Card#1] . Когда я просто запускаю программу, все работает нормально!
Я пытался добавить поле с @Version в элементы Card и Deck. Попробовал добавить @Transactional(propagation = NOT_SUPPORTED) поверх теста. Я думаю, ошибка возникает из-за того, что транзакция выполняется дважды.
CardEntity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "card")
public class Card {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "card_id")
private Long cardId;
@Column(name = "id_in_deck")
private Long idInDeck;
@Column(name = "term")
private String term;
@Column(name = "definition")
private String definition;
@ManyToOne
@JoinColumn(name = "deck_id")
private Deck deck;
}

Репозиторий карт
@Repository
public interface CardRepository extends JpaRepository {
Card findCardByIdInDeckAndDeck(long IdinDeck, Deck deck);

@Transactional
@Modifying
@Query(value = "INSERT into card (term,definition,id_in_deck,deck_id) " + "VALUES (:#{#card.term},:#{#card.definition},:#{#card.idInDeck},:#{#card.deck.deckId})", nativeQuery = true)
int insertCard(@Param("card") Card card);

@Transactional
@Modifying
@Query(value = "UPDATE Card SET term = :#{#card.term}, definition = :#{#card.definition} WHERE (deck_id = :#{#card.deck.deckId} AND id_in_deck =:#{#card.idInDeck})", nativeQuery = true)
void updateCard(@Param("card") Card card);

@Transactional
@Modifying
@Query(value = "DELETE FROM Card WHERE (deck_id = :#{#card.deck.deckId} AND id_in_deck =:#{#card.idInDeck})", nativeQuery = true)
void deleteCard(@Param("card") Card card);
}

Колода

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "deck")
public class Deck {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "deck_id")
private Long deckId;
@Column(name="title")
private String title;
@OneToMany(mappedBy = "deck", cascade = CascadeType.ALL,orphanRemoval = true)
private List cardList;

}

DeckRepository
@Repository
public interface DeckRepository extends JpaRepository {
Deck findDeckByTitle(String title);
}

DeckServiceImpl
@Service
@AllArgsConstructor
public class DeckServiceImpl implements DeckService {
public DeckRepository deckRepository;
public CardRepository cardRepository;
public final DeckMapper deckMapper;

@Override
@Transactional
public DeckDto createDeck(DeckDto deckDto) {
Deck deck = deckMapper.mapToDeck(deckDto);
deck.getCardList().forEach(card -> card.setDeck(deck));

Deck existingDeck = deckRepository.findDeckByTitle(deck.getTitle());
if (existingDeck != null) {
existingDeck.getCardList().sort(Comparator.comparing(Card::getIdInDeck));
long deckId = existingDeck.getDeckId();
deck.getCardList().forEach(card -> {
card.getDeck().setDeckId(deckId);
Card existingCard = cardRepository.findCardByIdInDeckAndDeck(card.getIdInDeck(), existingDeck);
if (existingCard != null) {
cardRepository.updateCard(card);
} else {
cardRepository.insertCard(card);
}
});

int sizeNewDeck = deck.getCardList().size();
int sizeOldDeck = existingDeck.getCardList().size();
boolean isNewDeckSmallerThanExisting = sizeNewDeck < sizeOldDeck;

if (isNewDeckSmallerThanExisting) {
Iterator cardListIterator = existingDeck.getCardList().listIterator(sizeOldDeck - sizeNewDeck);
while (cardListIterator.hasNext()) {
Card currentCard = cardListIterator.next();
cardRepository.deleteCard(currentCard);
}
Card currentCard = cardListIterator.next();
cardRepository.deleteCard(currentCard);
}
} else {
deckRepository.save(deck);
}

DeckDto savedDeckDto = deckMapper.mapToDeckDto(deck);
savedDeckDto.getCardList().forEach(cardDto -> cardDto.setDeckId(deck.getDeckId()));

return savedDeckDto;
}

Тест
DeckServiceImplTests
@SpringBootTest
@Import(DeckServiceImpl.class)
class DeckServiceImplTests {
@Autowired
private DeckServiceImpl deckService;

@Test
void shouldReturnSavedDeckDtoAndCreateDeck() throws Exception {
List cardDtoList = List.of(new CardDto(1L, 1L, "put", "класть", 1L), new CardDto(2L, 2L, "dig", "копать", 1L), new CardDto(3L, 3L, "cut", "резать", 1L));
DeckDto deckDto = new DeckDto(1L, "english", cardDtoList);
DeckDto savedDeckDto = deckService.createDeck(deckDto);
}

}

Полная ошибка

org.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.study.cardStudy.entity.Card#1]

at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:325)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:560)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:343)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
at jdk.proxy2/jdk.proxy2.$Proxy132.save(Unknown Source)
at com.study.cardStudy.service.impl.DeckServiceImpl.createDeck(DeckServiceImpl.java:59)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:380)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at com.study.cardStudy.service.impl.DeckServiceImpl$$SpringCGLIB$$0.createDeck()
at com.study.cardStudy.service.impl.DeckServiceImplTests.shouldReturnSavedDeckDtoAndCreateDeck(DeckServiceImplTests.java:27)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [ c o m . s t u d y . c a r d S t u d y . e n t i t y . C a r d # 1 ] < b r / > a t o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . e n t i t y I s D e t a c h e d ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 4 2 6 ) < b r / > a t o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . m e r g e ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 2 1 4 ) < b r / > a t o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . d o M e r g e ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 1 5 2 ) < b r / > a t o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . o n M e r g e ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 1 3 6 ) < b r / > a t o r g . h i b e r n a t e . e v e n t . s e r v i c e . i n t e r n a l . E v e n t L i s t e n e r G r o u p I m p l . f i r e E v entOnEachListener(EventListenerGroupImpl.java:138)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:875)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:846)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:258)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:248)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:570)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:492)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:253)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:604)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:534)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:495)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:253)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:192)
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:667)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:441)
at org.hibernate.event.internal.DefaultMergeEventListener.merge(DefaultMergeEventListener.java:214)
at org.hibernate.event.internal.DefaultMergeEventListener.doMerge(DefaultMergeEventListener.java:152)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:136)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:89)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:854)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:840)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:320)
at jdk.proxy2/jdk.proxy2.$Proxy124.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:630)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:515)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:284)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:752)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:174)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:149)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:69)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:380)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138)



Подробнее здесь: https://stackoverflow.com/questions/793 ... n-run-test
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»