Spring-Data-JPA атомарная вставка с зависимостями - PullRequest
0 голосов
/ 02 июля 2018

Я хочу вставить объекты в базу данных из масштабируемого микросервиса. Я пытался @Lock(LockModeType.PESSIMISTIC_WRITE) предотвратить двойные записи. Проблема в том, что у меня есть зависимости от моих сущностей.

Базовый пример:

TestEntity.java

public class TestEntity {

    @GeneratedValue()
    @Id
    private Long id;

    private String string;

    @ManyToOne
    private TestEntityParent testEntityParent;

}

TestEntityParent.java

public class TestEntityParent {

    @GeneratedValue()
    @Id
    private Long id;

    private String stringTwo;

    @OneToMany(mappedBy = "testEntityParent")
    private List<TestEntity> testEntities;

} 

TestEnityRepository.java

public interface TestEnityRepository extends JpaRepository<TestEntity,Long> {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    TestEntity saveAndFlush(TestEntity testEntity);

    Optional<TestEntity> findByStringAndTestEntityParentStringTwo(String string, String stringTwo);

}

TestEntityParentRepository.java

public interface TestEntityParentRepository extends JpaRepository<TestEntityParent, Long> {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    TestEntityParent save(TestEntityParent testEntityParent);

    Optional<TestEntityParent> findByStringTwo(String stringTwo);
}

AtomicDbService.java

@Service
public class AtomicDbService {

    @Autowired
    TestEnityRepository testEnityRepository;

    @Autowired
    TestEntityParentRepository testEntityParentRepository;

    @Transactional
    public TestEntity atomicInsert(TestEntity testEntity) {
        TestEntityParent testEntityParent = testEntityParentRepository.findByStringTwo(testEntity.getTestEntityParent().getStringTwo())
                .orElse(testEntityParentRepository.save(testEntity.getTestEntityParent()));

        return testEnityRepository.findByStringAndTestEntityParentStringTwo(
                testEntity.getString(), testEntity.getTestEntityParent().getStringTwo()
        ).orElse(testEnityRepository
                .save(
                        TestEntity.builder()
                                .string(testEntity.getString())
                                .testEntityParent(testEntityParent)
                                .build()
                )
        );
    }

}

Мой тестовый пример:

    @Test
    @Transactional
    public void testAtomicInsert(){

        TestEntityParent testEntityParent = TestEntityParent.builder().stringTwo("testTwo").build();
        TestEntity testEntity = TestEntity.builder().string("test").testEntityParent(testEntityParent).build();

        atomicDbService.atomicInsert(testEntity);
        System.out.println(testEnityRepository.findAll());
        atomicDbService.atomicInsert(testEntity);
        System.out.println(testEnityRepository.findAll());
        atomicDbService.atomicInsert(testEntity);
        System.out.println(testEnityRepository.findAll());

        System.out.println(testEnityRepository.findAll());

    }

Я получаю следующий ответ:

[TestEntity(id=2, string=test, testEntityParent=TestEntityParent(id=1, stringTwo=testTwo, testEntities=null))]
[TestEntity(id=2, string=test, testEntityParent=TestEntityParent(id=1, stringTwo=testTwo, testEntities=null)), TestEntity(id=3, string=test, testEntityParent=TestEntityParent(id=1, stringTwo=testTwo, testEntities=null))]

и ошибка:

query did not return a unique result: 2; 

Без зависимостей все работает нормально.

UPDATE:

Добавление @Lock(LockModeType.PESSIMISTIC_WRITE) к методу поиска приводит к

Feature not supported: "MVCC=TRUE && FOR UPDATE && JOIN"; SQL statement:

... то же самое относится к

 @Lock(LockModeType.PESSIMISTIC_WRITE)
 @Query("SELECT e from TestEntity e join e.testEntityParent p where e.string = :string and p.stringTwo = :stringTwo ")
 Optional<TestEntity> findWhatever(@Param("string") String string, @Param("stringTwo") String stringTwo);

... поскольку for update генерируется всегда.

1 Ответ

0 голосов
/ 02 июля 2018

Очевидно, это была глупая ошибка, мне нужно было заменить orElse на orElseGet и лямбду, и все работало, даже без всех этих @Lock и т. Д. Трюков.

Тем не менее, я не понимаю, что именно пошло не так с транзакциями и почему.

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